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+.
-
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.
http://codepen.io/anon/pen/KwOyQo
Friends, is there any way to make this div scroll even being with the mouse over the boxes??
Html:
<div class="container">
<div class="container-scroll">
<ul class="list">
<li class="list-item one"></li>
<li class="list-item two"></li>
</ul>
</div>
</div>
Css:
.container {
width: 100%;
height: 400px;
border: 1px solid black;
overflow: scroll;
color: white;
}
.container-scroll {
width: 100%;
height: 4000px;
}
.list {
list-style: none;
position: fixed;
}
.list-item {
display: inline-block;
width: 150px;
height: 150px;
}
.list-item.one {
background: pink;
}
.list-item.two{
background: black;
float: right;
}
I was trying to make something with overflow but anything worked..
You've set those elements to position: fixed. This positions the elements relative to the browser, which means they're completely taken out of the flow of their parent. So of course, when you hover over them, the container won't scroll.
You could use pointer-events: none on those boxes, but this isn't supported well across all browsers. Also, it's unclear whether you might actually need pointer events inside those elements in the future.
My advice would be to remove the scrollable div. Ensure that the body/document is the only element that scrolls. That way the content will scroll no matter what element you're currently mousing over.
.list-item {
display: inline-block;
width: 150px;
height: 150px;
pointer-events:none;
}
This will do the trick
EXAMPLE: http://codepen.io/anon/pen/OPKOog
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>
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
Using jQuery the jquery plugin along with the easing plugin.
I have a series of anchors, in a list which are all fixed heights and widths. Within each div is another I've called 'content', this is positioned absolute and slides into view, from the bottom, when the mouse enters the containing div. When the mouse leaves the containing div, the 'content' div slides back out of view.
I had this working, using a combination of top and bottom values but this doesn't work cross-browser (only works correctly in firefox from what I can tell). The code for this is below (html, css and javascript):
<!doctype html>
<head>
<style>
.index {
float: left;
margin: 0 0 30px 0;
margin-left: 0;
padding: 0;
position: relative;
}
.index li {
border: 2px solid #f3f3f3;
float: left;
list-style: none;
font-family:"Helvetica";
font-size:14px;
font-weight:normal;
margin: 0 10px 10px 0;
padding: 1px;
position: relative;
}
.index li a {
float: left;
height: 126px;
overflow: hidden;
position: relative;
width: 224px;
}
.index li img {
display: block;
}
.index li .content {
background: #f7f7f7;
bottom: auto;
display: block;
margin: 0;
padding: 10px 0 3px;
position: absolute;
top: 132px;
width: 224px;
}
.index li a:hover .content {
bottom: 0;
top: auto;
}
.index .content h3 {
background: url(../img/content/arw-sma.png) no-repeat 0 -100px;
color: #666;
margin: 0 10px 1px;
padding-left: 20px;
}
.index .content p {
color: #999;
display: block;
float: left;
font-size: 12px;
margin: 0 10px 2px;
padding: 0;
}
</style>
<script src="js//jquery-1.6.2.min.js"></script>
<script src="js/jquery.easing.js"></script>
<script type="text/javascript">
$(function(){
$('.index .content').css( {'top':'132px', 'bottom':'auto'});
$('.index li a').hover(
function(){
$(this).find('img').animate({'opacity': '.7'}, 200);
$(this).find('.content').animate({'bottom':'0'}, 150).css({'top':'auto'});
},
function(){
$(this).find('img').animate({'opacity': '1.0'}, 200);
$(this).find('.content').animate({'top':'132px'}, 150);
}
);
});
</script>
</head>
<body>
<ul class="index panel">
<li>
<a href="#" title="TITLE TEXT.">
<img src="thumb-1.jpg" alt="ALT TEXT." />
<div class="content">
<h3>Title Here</h3>
<p>Other content goes here</p>
</div>
</a>
</li>
<li>
<a href="#" title="TITLE TEXT.">
<img src="thumb-1.jpg" alt="ALT TEXT." />
<div class="content">
<h3>Title Here</h3>
<p>Other content goes here</p>
</div>
</a>
</li>
<li>
<a href="#" title="TITLE TEXT.">
<img src="thumb-1.jpg" alt="ALT TEXT." />
<div class="content">
<h3>Title Here</h3>
<p>Other content goes here</p>
</div>
</a>
</li>
</ul>
</body>
Different browsers don't like using both top and bottom values. So ideally, I'm guessing I need to just use 'top'. The problem is, I don't know how tall the 'content div' will be, so I can't set an explicit value, as if its taller, it will chop off some of the content.
Since I know the anchor will be 126 pixels in height. I've been trying to use .height() to detect the height of the 'content div'. Then subtract this value from 126 - which would leave me with the value I need to set 'top' to be, to position it within the div.
Does this sound plausible and am I making sense? Hopefully this isn't to long winded, just trying to be as detailed as I can.
Hope someone can help and I love forward to you replies!
demo jsBin
Use SPAN instead of DIV (DIV are block level elements, and AFAIK it won't validate your document.)
You can just set an initial bottom value like -132...-150 ...or whatever you prefer for your .content
.index li .content {
background: #f7f7f7;
bottom: -132px;
display: block;
margin: 0;
padding: 10px 0 3px;
position: absolute;
top: 132px;
width: 224px;
}
jQ:
$(function(){
$('.panel li a').hover(
function(){
$(this).find('img').animate({'opacity': '.7'}, 200);
$(this).find('.content').animate({'bottom':'0'}, 150).css({'top':'auto'});
},
function(){
$(this).find('img').animate({'opacity': '1.0'}, 200);
$(this).find('.content').animate({'bottom':'-132px'}, 150);
}
);
});
THe other solution I would use is to: at DOM ready, calculate each content height ( var outerH = $(this).outerHeight(true) ) and set that value as a data-height for each element. ($(this).data('height', outerH);). Than you can animate on hover the exact N of px that is stored in that element data-height.