I have a ul
with fixed height, which contian dynamic number of li
elements, if too many a scrollbar appaers. You can select a li
element by clicking on it.
What I want is the li
element that is active to be fixed at the top if scrolling aboveit or fixed at the bottom if scrolling below it, so the active li
element is always showing, and the other li
elements just scrolls past the active one.
I have made a plunker. I am using Angular, and I dont know if this can be solved just using CSS or if I need a directive etc. for this.
Html:
div class="parent">
<div class="child1">
<input ng-model="vm.query" type="text" placeholder="Search" />
<ul >
<li ng-repeat="todo in todos" ng-class="{'active': todo.active}" ng-click="activeTodo($index)">
<a>{{todo.name}}</a>
</li>
</ul>
</div>
CSS:
.parent{
display: flex;
}
.child1{
background-color: #eeeeee;
height: 500px;
overflow:scroll;
}
.active{
background-color: red;
position:fixed;
}
Thanks in advance!
I have a ul
with fixed height, which contian dynamic number of li
elements, if too many a scrollbar appaers. You can select a li
element by clicking on it.
What I want is the li
element that is active to be fixed at the top if scrolling aboveit or fixed at the bottom if scrolling below it, so the active li
element is always showing, and the other li
elements just scrolls past the active one.
I have made a plunker. I am using Angular, and I dont know if this can be solved just using CSS or if I need a directive etc. for this.
Html:
div class="parent">
<div class="child1">
<input ng-model="vm.query" type="text" placeholder="Search" />
<ul >
<li ng-repeat="todo in todos" ng-class="{'active': todo.active}" ng-click="activeTodo($index)">
<a>{{todo.name}}</a>
</li>
</ul>
</div>
CSS:
.parent{
display: flex;
}
.child1{
background-color: #eeeeee;
height: 500px;
overflow:scroll;
}
.active{
background-color: red;
position:fixed;
}
Thanks in advance!
Share Improve this question edited Dec 22, 2015 at 7:46 Devl11 asked Dec 20, 2015 at 21:25 Devl11Devl11 2212 silver badges10 bronze badges 1- This is not achievable via CSS only. The logic is quite simple, really: on parent scroll check position of active element and determine if it's in view or not. If it's not, change its position to fixed (top or bottom) and (eventually) set a top/bottom padding on the parent. Would you like us to code it for you? If yes, please provide a reason. Preferably a good one. – tao Commented Dec 20, 2015 at 21:44
3 Answers
Reset to default 2I managed this using some CSS and making a directive.
Made a plunker here.
I made a directive which every li
element got. Then with jquery in the directive I get the necessary elements like the div
which have the scroll, the current li
element etc.
Two booleans for checking if the li
is fixed at the top or bottom. And then just check if the current scrollPosition(scrollTop) is higher or lower then the current li
element. And it also check so the li
element got the active boolean attached too it.
return {
restrict: 'A',
link: function($scope, element, attributes){
var scrollDiv = $('#scrollDiv'),
liElement = element,
liElementTop = parseInt(liElement.offset().top),
scrollDivTop = parseInt(scrollDiv.offset().top),
isFixedTop = false,
isFixedBottom = false;
liElement.width(scrollDiv.width());
scrollDiv.on('scroll', function(){
var scrollTop = scrollDiv.scrollTop();
if (!isFixedBottom && !isFixedTop && scrollTop <= liElementTop - (scrollDivTop+(scrollDiv.height()-liElement.height())) && liElement.hasClass("active")) {
isFixedBottom = true;
liElement.css({'position': 'fixed', 'top': scrollDivTop+(scrollDiv.height()-liElement.height()+1),'list-style-type':'none','z-index':'10'});
} else if (isFixedBottom && !isFixedTop && scrollTop >= liElementTop - (scrollDivTop+(scrollDiv.height()-liElement.height()))) {
isFixedBottom = false;
liElement.css({'position': 'static', 'top': 0});
}
else if (!isFixedTop && !isFixedBottom && scrollTop >= liElementTop - scrollDivTop && liElement.hasClass("active")) {
isFixedTop = true;
liElement.css({'position': 'fixed', 'top': scrollDivTop,'list-style-type':'none','z-index':'10'});
}
else if (isFixedTop && !isFixedBottom && scrollTop <= liElementTop - scrollDivTop) {
isFixedTop = false;
liElement.css({'position': 'static', 'top': 0});
}
})
}
};
The consideration of using pure CSS: One of the best solution is this, because those who perhaps want to make an element remain fixed while it is scrolling up and down!
body {
margin: 10px;
}
ul {
display: block;
width: 210px;
max-height: 120px;
overflow-y: auto;
margin: 0;
padding: 0;
}
li {
padding: 8px 10px;
display: block;
font-size: 13px;
cursor: pointer;
background-color: #ddd;
}
li.fixed {
position: -webkit-sticky;
position: sticky;
bottom: 0;
background-color: #111;
color: #f2f2f2;
}
<ul>
<li>Item1</li>
<li>Item2</li>
<li>Item3</li>
<li>Item4</li>
<li>Item5</li>
<li>Item6</li>
<li>Item7</li>
<li>Item8</li>
<li>Item9</li>
<li>Item10</li>
<li>Item11</li>
<li>Item12</li>
<li>Item13</li>
<li>Item14</li>
<li>Item15</li>
<li>Item16</li>
<li>Item17</li>
<li>Item18</li>
<li>Item19</li>
<li>Item20</li>
<li>Item21</li>
<li>Item22</li>
<li>Item23</li>
<li>Item24</li>
<li>Item25</li>
<li>Item26</li>
<li>Item27</li>
<li>Item28</li>
<li>Item29</li>
<li>Item30</li>
<li>Item31</li>
<li>Item32</li>
<li>Item33</li>
<li>Item34</li>
<li>Item35</li>
<li>Item36</li>
<li>Item37</li>
<li>Item38</li>
<li>Item39</li>
<li>Item40</li>
<li>Item41</li>
<li>Item42</li>
<li>Item43</li>
<li>Item44</li>
<li>Item45</li>
<li>Item46</li>
<li>Item47</li>
<li>Item48</li>
<li>Item49</li>
<li>Item50</li>
<li class="fixed">HEADER</li>
</ul>
If I understood you correctly you like the active div on top.
to solve this in css
use position:relative
on parent and position:absolute
on the child element with top:0