I have a div which has to scroll. The problem is that it's within a fixed div.
I tried to fix this in different ways, I went through these posts:
Div with scrollbar inside div with position:fixed
Have a fixed position div that needs to scroll if content overflows
but none of them worked for me.
I'd like to test it with you guys and find out what's the problem.
I am working on a mobile responsive website.
It has a nav menu button that opens .list div up - when clicking the menu button.
I inserted the div of the .list right after the nav bar.
When the menu opens it doesn't show all list items in my tag.
I have to give my main div .list different height sizes and I find it not so efficient.
I will paste my relevant code part of the nav bar, and the relevant CSS parts.
HTML:
<div class="list">
<h2 id="cat-header"> ALL CATEGORIES</h2>
<ul class="sports">
<li class="mainli"></li>
<li class="mainli"></li>
<li class="mainli"></li>
</ul>
</div>
CSS:
.sports{
/*display: none;*/
padding: 0 ;
background-color: #fff;
margin: 0;
width:100%;
/*height: 210%*/
-webkit-overflow-scrolling: touch;
}
.list{
width: 99.9%;
/* overflow: hidden; */
/* overflow-y: scroll; */
/* top: 65%; */
overflow-x: hidden;
/*overflow-y: scroll;*/
height: 75%;
display: none;
-webkit-overflow-scrolling: touch;
}
when clicking #mob-menu-btn it opens .list and makes my whole tag fixed:
$('#mob-menu-btn').click(function(){
var isHidden = $('.sports').is(':visible');
if (isHidden){
$( "body" ).removeClass( "makeFixed" );
} else {
$( "body" ).addClass( "makeFixed" );
}
$('.list').slideToggle("fast");
})
my .makeFixed looks like this:
.makeFixed{
position: fixed;
}
I tested this last, and it didn't solve my problem:
.makeFixed{
position: fixed;
top: 0;
bottom:0;
overflow-y:scroll;
overflow-x:hidden;
}
and changed height: auto; and overflow-y: scroll; within .sports and .list.
What might be the problem?
I have a problem with the following:
if (isHidden){
$( "body" ).removeClass( "makeFixed" );
} else {
$( "body" ).addClass( "makeFixed" );
}
having the following CSS:
.makeFixed{
position: fixed;
}
Which means you are fixing the body to... the body? Here is my suggestion:
// I'll keep your HTML intact
<div class="list">
<h2 id="cat-header"> ALL CATEGORIES</h2>
<ul class="sports">
<li class="mainli"></li>
<li class="mainli"></li>
<li class="mainli"></li>
</ul>
</div>
// Your list will be your fixed element. It might be better to call this your nav.
.list {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 0;
transition: height 500ms;
overflow-x: hidden;
}
// I add an active state for it. It will also nicely animate thanks to the previously named transition.
.list.active {
height: 99%;
}
// I only toggle the .active class on the click of the mobile button
$('#mob-menu-btn').click(function(){ $(".list").toggleClass("active"); });
This way you simplify your menu quite a bit. You animate with CSS, you have a simple wrapper that determines where your menu will be positioned and how, and the contents will push the overflow to be scrollable if they are larger.
Also, 'overflow: auto' is unnecessary, I have not come across a need for this. Heres an example where the yellow area is fixed to be very heigh so the scrolling will work, but the gist is the same (actually, I've adjusted all values to make the example more visually obvious):
window.onload = function(){
document.getElementById("button").addEventListener("click", function(){
if(document.getElementById("list").className == "active"){
document.getElementById("list").className = "";
} else {
document.getElementById("list").className = "active";
}
});
}
#list {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 0;
transition: height 500ms;
overflow-x: hidden;
background: blue;
}
#list.active {
height: 80%;
}
#list ul {
height: 3000px;
background: yellow;
}
#button {
z-index: 4;
position: absolute;
top: 10px;
left: 10px;
background: #fff;
}
<div id="button">click me</div>
<div id="list">
<h2 id="cat-header"> ALL CATEGORIES</h2>
<ul class="sports">
<li class="mainli"></li>
<li class="mainli"></li>
<li class="mainli"></li>
</ul>
</div>
Use overflow: auto; on the div that you want to scroll, if the div have right height this will work
Give the height to the div with overflow-y:scroll !important and
like
write your div like this..
<div style="overflow-y:scroll !important;height:80px;">
/*your scrollable content
</div>
Try position the list by using
.list{
width: 99.9%;
/* overflow: hidden; */
/* overflow-y: scroll; */
/* top: 65%; */
overflow-x: hidden;
/*overflow-y: scroll;*/
height: 75%;
display: none;
-webkit-overflow-scrolling: touch;
position: fixed;
z-index:99999;
}
Try this..
<h2 id="cat-header">ALL CATEGORIES</h2> <div style="overflow-y:scroll ;height:80px;border:1px solid #000"> <ul class="sports"> <li class="mainli">hello</li> <li class="mainli">hello</li> <li class="mainli">hello</li> </ul> </div>
Related
How to apply a transform to element without affecting position: absolute sibling. Been playing with this for a few hours to no avail. I think the code will explain clearer than I can put into words.
The below works as intented, until transform: translateX(10px) is applied to the ul. I need the transform to move the ul based on screen size, it's a longer list in reality. Can the hover state be preserved? Thanks, webstudent
.relative {
position: relative;
}
nav {
min-width: 100vw;
height: fit-content;
overflow: hidden;
}
ul {
display: block;
min-width: 100vw;
list-style-type: none;
margin: 0;
padding: 0;
/* breaks stacking order */
/* transform: translateX(10px); */
}
li {
display: inline-block;
}
li a {
display: block;
padding: 4px 8px;
font-size: 1rem;
max-height: 1rem;
}
li a:hover {
background-color: red;
}
.absolute-sibling {
position: absolute;
left: 0;
top: calc(1rem + 8px);
width: 100vw;
height: fit-content;
display: none;
}
li a:hover + .absolute-sibling,
.absolute-sibling:hover {
background-color: red;
display: block;
}
<div class="relative">
<nav>
<ul>
<li>
<a>text one</a>
<!-- absolute child of .relative -->
<div class="absolute-sibling">content one</div>
</li>
<li>
<a>text two</a>
<!-- absolute child of .relative -->
<div class="absolute-sibling">content two</div>
</li>
<li>
<a>text three</a>
<!-- absolute child of .relative -->
<div class="absolute-sibling">content three</div>
</li>
</ul>
</nav>
</div>
Broken version with transform included, jsfiddle to reduce wall of code. Same code, apart from transform: translate(10px);
Update:
This describes the issue I'm trying to counter CSS stacking contexts
Also, for instance if I replace the transform: translateX(10px); with margin-left: 10px; everything is as intended. Just I'd like to use the transform for animation smoothness.
Heres one more solution, set the transform on your parent component div.relative and remove it from the ul. (you could also wrap that div and transform that if it works better for your layout)
Change this line in your css
.relative {
position: relative;
transform: translateX(10px)
}
If this still breaks your design then you need to rethink your HTML. As per your article setting a transform creates a new stacking context causing these weird effects. By setting the transform on a parent or wrapper element then you are moving that context up the chain and the child elements should behave like normal.
I Have created simple dropdown menu, where sub-menu is full width
jsFiddle
$(document).ready(function(){
$(".drop").hide();
$(".link-1").mouseenter(function(){
$('.link-1-drop').slideDown("fast");
});
$(".link-1").mouseleave(function(){
$('.link-1-drop').slideUp("fast");
});
});
https://jsfiddle.net/814z6eL5/2/
As both are different DIVs , when we mouse out to link and mouse enter to div container ,container div slides up.
Is there any way to keep the drop-down div open while move mouse to container?
You can put the div inside the li so when you hover over the container you are still hovering over the li. You can then use position:absolute; on the div.
https://jsfiddle.net/814z6eL5/4/
wrap the both li and slide in one element and assign event to wrapper element.
Check in jsFiddle code here
Mouseenter code
You could add a condition to see if the .link-1-drop is hovered. And if YES then do not close it, if NO , close it ( when leaving the link1)
See below
$(document).ready(function() {
$(".drop").hide();
$(".link-1").mouseenter(function() {
$('.link-1-drop').slideDown("fast");
});
$(".link-1").mouseleave(function() {
setTimeout(function() {
if (!$('.link-1-drop').is(':hover')) {
$('.link-1-drop').slideUp("fast");
}
}, 100);
});
});
*{
margin: 0;
padding: 0;
}
.main-nav{
width: 400px;
display: block;
background-color: #ccc;
margin: 0 auto;
height:20px
}
.drop{
width: 100%;
height: 250px;
background: #0ff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="main-nav">
<li class="link-1">Link 1</li>
</ul>
<div class="link-1-drop drop">
drop down content
</div>
<script
src="https://code.jquery.com/jquery-1.12.4.min.js"
integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
crossorigin="anonymous"></script>
If you want to that your code take effect without putting your div inside the Main-div
just make sur the li has same hight as the div container and check when you leave the li if the mouse hover the drop div or not as below code
$(document).ready(function(){
$(".drop").hide();
$(".link-1 ").mouseenter(function(){
$('.link-1-drop').slideDown("fast");
});
$(".link-1").mouseleave(function(){
if($(".link-1-drop:not(:hover)").length>0)
$('.link-1-drop').slideUp("fast");
});
$(".link-1-drop").mouseleave(function(){
if($(".link-1:not(:hover)").length>0)
$('.link-1-drop').slideUp("fast");
});
});
*{
margin: 0;
padding: 0;
}
.main-nav{
width: 400px;
display: block;
background-color: #ccc;
margin: 0 auto;
/*commented height to match li height */
/* height:20px;*/
}
.drop{
width: 100%;
height: 250px;
background: #0ff;
position:absolute;
left:0;
right:0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="main-nav">
<li class="link-1">Link 1</li>
</ul>
<div class="link-1-drop drop">
drop down content
</div>
Otherwise and better , just put your drop div inside the li , and make css change by adding to
.drop {
...
position:absolute;
left:0;
}
As bellow Snippet :
$(document).ready(function() {
$(".drop").hide();
$(".link-1 ").mouseenter(function() {
$('.link-1-drop').slideDown("fast");
});
$(".link-1").mouseleave(function() {
$('.link-1-drop').slideUp("fast");
});
});
* {
margin: 0;
padding: 0;
}
.main-nav {
width: 400px;
display: block;
background-color: #ccc;
margin: 0 auto;
height: 20px
}
.drop {
width: 100%;
height: 250px;
background: #0ff;
position: absolute;
left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="main-nav">
<li class="link-1">Link 1
<div class="link-1-drop drop">
drop down content
</div>
</li>
</ul>
I'm having some trouble with my Pagination nav that is display:none. When I check on inspect element it takes no space, but for some reason, where the pagination nav is, there's an empty space that is not supposed to be there.
I've tried adding overflow:hidden, visibility:none, height:0, but none of it it's working.
Maybe it's something to do with position relative and absolute, I don't understand it very well yet.
themeexp1.tumblr.com
Edit: It's not the 14px margin, it's a much bigger margin
Empty space: http://postimg.org/image/hiixhonoh/
HTML
<div id="content">
<div class="container" id="{postID}">
<div class="container-overlay"></div>
<div class="photo inner">
<a href="{permalink}">
<img src="{block:indexpage}{PhotoURL-500}{/block:indexpage}{block:permalinkpage}{PhotoURL-HighRes}{/block:permalinkpage}" alt="{PhotoAlt}">
</a>
</div>
</div>
<nav id="pagination">
<ul>
{block:PreviousPage}<li>Previous page</li>{/block:PreviousPage}
{block:NextPage}<li><a id="nextPage" href="{NextPage}">Next page</a></li>{/block:NextPage}
</ul>
</nav>
</div>
CSS
#content{
margin: 0 auto;
position: relative;
}
.container{
margin-bottom: 14px;
}
.container-overlay{
width: 100%;
height: 100%;
opacity: 0;
position:absolute;
}
.icons{
opacity: 0;
position: absolute;
left: 50%;
top: 50%;
width: 100%;
text-align: center;
}
#pagination{
display: none;
position: absolute;
}
It's hard to tell what you want without a demo, but there is space at the bottom because your .container div has margin-bottom: 14px;.
Example Fiddle
This is a very simple example of sticking an element at the top of another element's visible area. When .container is scrolled, .fixed stays at the top.
<div class="container">
<div class="fixed">fixed content</div>
<div class="content">regular content<br/>regular content<br/>regular content<br/>regular content<br/>regular content</div>
</div>
<style type="text/css">
.container {
position: relative;
border: 1px solid blue;
overflow: auto;
width: 250px;
height: 250px;
}
.content {
height: 500px;
width: 500px;
}
.fixed {
position: absolute;
width: 500px;
margin-top: 2rem;
border 1px solid red;
}
</style>
<script type="text/javascript">
$('.container').scroll(function () {
var top = $('.container').prop('scrollTop');
console.log(top);
$('.fixed').css('top', top);
});
</script>
The problem with this is that if the browser is not fast enough, the .fixed element flickers when I scroll. It lags behind the scroll (compare the position of the text in .fixed to the text in .content as you're scrolling). On my desktop it works flawlessly, but when I try running this in Chromium in a virtual machine, I can see the flicker.
Is there any other way to catch the scroll event and set the position of my .fixed element before the browser renders the page?
edit Updated example to include horizontal scrolling. The fixed element should only be fixed vertically.
Use a double container:
<div class="container-wrapper">
<div class="fixed">fixed content</div>
<div class="container">
<div class="content">regular content<br/>regular content<br/>regular content<br/>regular content<br/>regular content</div>
</div>
</div>
With the CSS:
.container-wrapper {
position: relative;
border: 1px solid blue;
overflow: hidden;
width: 250px;
height: 250px;
}
.container {
overflow: auto;
width: 100%;
height: 100%;
}
.content {
height: 500px;
}
.fixed {
position: absolute;
top: 0px;
left: 0px;
width: 245px;
border 1px solid red;
z-index: 10;
}
This way you won't need jQuery to reposition the .fixed div when you scroll, and it won't flicker.
EDIT To address the horizontal scrolling...
$('.container').on('scroll', function() {
var left = this.scrollLeft;
$('.fixed').css('left', -left + 'px');
});
This should move the .fixed div without flickering. In your solution, the flickering was caused because the browser moved your div while scrolling, and the event handler then moved it again. Now it will only move once.
I want to have horizontal lists that can run as wide as possible but within a fixed width container. I am using jQuery to allow scrolling on the really wide list, and overflow:automatic for users without javascript.
I have code along the lines of this:
<div class="list">
<ul>
<li class="feed">
<section>
<h1><span class="name">Title</span></h1>
<div class="scroll_left"><a class="ir" href="#">Scroll Back</a></div>
<div class="article_list">
<ul class="article_list">
<li>
<a href="article.php">
<div class="article_thumb"><img src="img/placeholder.png" alt="blah" /></div>
<h2>Title of article</h2>
</a>
</li>
<li>
<a href="article.php">
<div class="article_thumb"><img src="img/placeholder.png" alt="blah" /></div>
<h2>Title of article</h2>
</a>
</li>
<li>
<a href="article.php">
<div class="article_thumb"><img src="img/placeholder.png" alt="blah" /></div>
<h2>Title of article</h2>
</a>
</li>
<!-- variable number of li's, from 10s to 100s -->
</ul>
</div>
</section>
</li>
<!-- More of these lists -->
</ul>
</div>
I'll just give a subset of my css that I think is relevant:
.feed .article_list {
position: relative;
overflow: auto;
float: left;
width: 900px;
}
.feed .article_list ul {
position: relative;
width: 10000px; /** I want this to be wide, but not allow scrolling past the end*/
margin: 0;
background-color: #ffffff;
}
.feed .article_list li {
display: block;
width: 130px;
height: 150px;
position: relative;
float: left;
border-right: 2px solid #b5e8f4;
border-left: 2px solid #b5e8f4;
margin: 0 5px 0 0;
}
My javascript is:
$(document).ready(function() {
$('div.article_list').css({
'overflow' : 'hidden'
});
$('.scroll_left a').click(function() {
toScroll = $(this).parent().next();
toScroll.animate({scrollLeft: "-=135"});
return false;
});
$('.scroll_right a').click(function() {
toScroll = $(this).parent().prev();
toScroll.animate({scrollLeft: "+=135"});
return false;
});
});
So as it is, I either have to make the inner ul really wide, so users can scroll well beyond the list items, or I can restrict it but if I add too many items (dynamically, so I don't have a lot of control), then the layout breaks.
Can I somehow get that scrollable area to just be as wide as its floated contents?
Or is the only solution to set the width in javascript (less than ideal, but I can do that)?
Its the float: left on the .feed .article_list that you really don't want but I've removed it from all of them that I could.
I would move to an inline setup instead of floating:
.feed .article_list {
position: relative;
overflow: auto;
width: 100%; /* specify what ever width you want. I think 100% is proper. */
}
.feed .article_list ul {
position: relative;
overflow-x: scroll;
margin: 0;
background-color: #ffffff;
white-space: nowrap;
}
By making the overflow-x: scroll you have a permanent scroll bar (not totally necessary, it can be removed if you prefer). The white-space: nowrap Will keep the children on one line (instead of floating.)
.feed .article_list li {
display: inline-block;
// etc. etc. etc. ...
on the children display: inline-block; will let you specify height/width like a block element and keep them inline at the same time.
JsFiddle:- http://jsfiddle.net/GBtCb/
UPDATE :-
In an effort to make it cross-browser compatible make the following changes:
remove the overflow: auto from .feed .article_list
and add:
.feed
{
overflow: hidden;
}
.article_list
{
overflow: auto;
from quirksmode.com:
http://www.quirksmode.org/css/whitespace.html : white-space: nowrap is compatible IE7+.
-