I have this HTML code:
<div class="header">
<div class="desc">Description</div>
<div class="logo"><img src=""/></div>
<div class="navbar"></div></div>
.header has a height of 150px. .navbar has a height of 20px. When the user scrolls, I want .navbar to stick at the top. So I went to the CSS and set position:sticky and top:0. But this didn't work. I initially thought that firefox is not supporting position:sticky, but that's not the case because I was able to see a working demo of it. I googled about it but found nothing helpful. Anyone knows why this is not working?
Position sticky was not working for me due to the body element having overflow-x: hidden; set.
The 2 most common culprits why position: sticky; might not work are:
You haven't defined top: 0;, bottom: 0;, left: 0 or something similar
One of the parents of your sticky element has overflow (x or y) set to hidden, scroll or auto.
For me it was the first one.
It works fine if you move the navbar outside the header. See below. For the reason, according to MDN:
The element is positioned according to the normal flow of the document, and then offset relative to its flow root and containing block based on the values of top, right, bottom, and left.
For the containing block:
The containing block is the ancestor to which the element is relatively positioned
So, when I do not misunderstand, the navbar is positioned at offset 0 within the header as soon as it is scrolled outside the viewport (which, clearly, means, you can't see it anymore).
.navbar {
background: hotpink;
width: 100%;
height: 50px;
position: sticky;
top: 0;
}
.header {
height: 150px;
background: grey;
}
body {
height: 800px;
position: relative;
}
<div class="header">
<div class="desc">Description</div>
<div class="logo"><img src="" /></div>
</div>
<div class="navbar"></div>
To expand from the answers above and some information to make it work with flexbox parent and overflow other than visible (the examples below assume you use vertical - sticky with either top or bottom set to a certain value and position set to sticky):
The most frequent case is you have an ancestor element (not just immediate parent) with overflow property set to something other than visible and as a result there is no space is left to stick around.
To quickly find out if this is the case, you can run this script in the browser console (please make sure you change the .your-sticky-element class to your element's selector):
var stickyElement = document.querySelector('.your-sticky-element');
var parent = stickyElement.parentElement;
while (parent) {
var hasOverflow = getComputedStyle(parent).overflow;
if(hasOverflow != 'visible') {
console.log(hasOverflow, parent);
}
parent = parent.parentElement;
}
SOLUTION:
a) If you found there is overflow set, and you can remove it, this should solve it
b) If you have to keep your overflow setting, you have to make the parent element's height higher than the sticky element's height. If the parent element has no height or the sticky element fills up all the height, it means there is simply no place to stick within when the page is scrolled. It doesn't need to an explicit height (vertical), but you can inspect to see if your sticky element has extra space left after itself.
Parent is not higher than the sticky element to leave extra space. This particular case can be caused by different circumstances but the solution to this is the same above, please see 1.b
If your sticky element's parent is a flexbox (align-items has default value of normal) or grid, and if the sticky element itself doesn't have a proper align-self set, there will be no space left for the sticky element to hold when scrolling (for example, if it is align-self: stretch or auto [default value]). This is because the child element is stretched to fill up the height of the parent.
SOLUTION:
In this case, align-self: flex-start set for the sticky element can fix the problem because in the element will stand at the start, leaving extra space after itself.
Guide: There are much more complex circumstances both in the case of flexboxes and without it, but the general rule of thumb is your sticky element needs space within the parent to be sticky when scrolled.
Somehow your code only works when the .navbar element is not inside another container like the header. I moved it out and then it works fine. I created a codepen snippet for that, check it out
<header>
<div class="logo">Logo</div>
<div class="description"><div>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo, veritatis.</div></div>
</header>
<div class="navbar">
<ul>
<li>navitem1</li>
<li>navitem2</li>
<li>navitem3</li>
<li>navitem4</li>
</ul>
</div>
Right now position:sticky is supported quite good as you can see on canIuse. Of course IE currently has no support but the new Edge version will bring full support for this! I found some interesting articles about this topic:
Working demo (chrome,firefox 👍) https://codepen.io/simevidas/pen/JbdJRZ
Caniuse refernce: http://caniuse.com/#search=sticky
sticky article on MDN including latest browser support table https://developer.mozilla.org/en-US/docs/Web/CSS/position#Sticky_positioning
But there are good news on the horizon. I think better browser support will follow the next time.
Adding more content after nav inside header provides sticky behavior, but only for a moment - if the user scrolls down too much, nav will disappear with header, since it can't jump out below header's bottom border.
Thus, the only solution with pure CSS is to put nav inside element that is partially visible even after the user scrolls to the bottom of the page (directly inside body or inside some sort of container that spans to the bottom of the page or at least to the footer).
If this solution is not possible, the other way is to use JavaScript. Before transitioning to CSS, I used the following code (found similar jQuery solution somewhere long time ago, don't remember where, so the credit goes to the anonymous author; Vanilla JS can be easily obtained from this):
$(document).ready(function () {
var sticky_navigation_offset_top = $('nav').offset().top;
var sticky_navigation = function () {
var scroll_top = $(window).scrollTop();
if (scroll_top > sticky_navigation_offset_top) {
$('nav').css({
'position': 'fixed',
'top': 0,
'left': 0,
'right': 0,
'margin-left': 'auto',
'margin-right': 'auto'
});
} else {
$('nav').css({
'position': 'relative'
});
}
};
sticky_navigation();
$(window).scroll(function () {
sticky_navigation();
});
});
Looks like if you try to set sticky a container which has many children nodes inside, instead of them being wrapped in a div, and the parent of sticky container is flex, then it will not sticky. Just wrap the childs in a div fixed it for me.
Your HTML code as it is and write CSS class for navigation bar:
.header {
height: 150px;
background-color: #d1d1d1;
}
.navbar {
background: #999;
border-bottom: 1px solid #333;
border-top: 1px solid #333;
color: #FFF;
margin: 0;
padding: 2px 0 0 12px;
position: sticky;
top: -1px;
}
<div class="header">
<div class="desc">Description</div>
<div class="logo"><img src="" /></div>
<div class="navbar"></div>
</div>
Hope this will help
Met some not evident behaviour of horizontal sticky: if width is 100%, then sticky does not work. Width should be less, then container size.
My sticky header would only partly work ... after a couple of scrolls it would disappear but would work initially
It appears the problem was that I had the parent set to height 100%.
I didn't actually need this as the body one was enough so I removed and it and all was good.. sticks forever
Although this now breaks my footer from staying on the bottom when their is no content!
No huge compromises of the HTML structure need to be made to fix this issue. Simply add display: inline; to all of the sticky element's parents up until you get to the element you wish the sticky element to stick to.
Just to add something to #user56reinstatemonica8 great point...
If immediate parent of sticky node has display: flex sticky positioning could not work.
My guess is that culprit is align-items: stretch as default.
In a flex-direction: row scenario, align-items: stretch let children's height grow so that they are equal height.
So, to overcome this and make sticky work as expected with display: flex you can:
define align-items as center | start | baseline to immediate parent that has display: flex.
define align-self as center | start | baseline to sticky node.
define an explicit height to sticky node.
Is it possible to set the hitbox of an element when using -webkit-transform:scale(4);?
http://jsfiddle.net/bnA7L/
In the jsfiddle example above I have two divs. WHen you rollover one, you need to move your mouse to the edge of the new boundary to get it to return to its original size.
I want it to return to its original size as soon as the user's mouse moves out of the original hitbox.
It can be done in CSS when you add 2 children for each div.
Child 1 doesn't scale and acts as hitbox.
Child 2 scales, only when you hover over child 1.
http://jsfiddle.net/willemvb/q7vbD/
The pointer-events property makes this very easy.
First, wrap your content with a parent and a child:
<div class="parent">
<div class="child">
Hover me
</div>
</div>
Then, disable pointer events on the child, which allows pointer events to drip down to the parent element. Then use the parent's :hover pseudo-class to transform the child:
.child {
pointer-events: none;
}
.parent:hover .child {
transform: scale(4);
}
The parent remains its original size, so the "hitbox" for the hover effect remains at the original size, too.
You'll have to use jQuery or JavaScript to check the co-ordinates prior to the transform, and then listen out for the mousemove event on the DOM.
I am having trouble with elements inside an updatepanel losing their styles when the updatepanel refreshes. I know this isn't a new question and have already read the following threads
Someguys Blog on it
And another thread on it
And the possible work-arounds include: surround the update panel with a div, surround the update panel with a div.
This doesn't really work in my case because I have several elements inside my update panel but I want to only apply the style to two elements inside it and this method makes every element inside the update panel reflect the styles.
Any suggestions would be appreciated
-J
You can use a class on a surrounding div to control the style on elements inside the div. Put classes on some elements inside to identify them, and change the class on the surrounding div to trigger the change.
Example:
<div id="container" class="hide">
This is the content that can change
<div class="someelement">asf</div>
<div>qwer</div>
<div class="otherelement">uyhgf</div>
</div>
You can change the class on the outer div:
document.getElementById('container').className = 'show';
Now you can set up CSS rules to show changes on the inner elements depending on the outer class:
.hide .someelement { display: none; }
.show .someelement { display: block; }
.hide .otherelement { color: yellow; }
.show .otherelement { color: black; }
When the timer replaces the content the inner elements will still look the same, as the class controlling the appearence is on the outer div.
There are my codes. (jsfiddle)
Why this part of my codes isn't running?
header{background-color: #2bd5ec;}
I want to add background color to header tag. What i need to do?
The issue here is that since the elements inside your header are floated, they're considered in a different flow than your header, and thus it doesn't resize to fit them.
One way to fix this is to append <div style = "clear: both;"></div> to your header; little demo: little link.
You can also just add overflow: hidden; to your header: another little link, or float it as well: yet another little link.
you can set Height for Header.
for example :
header{background-color: red; height:100px;}
and you can use "clear" like this :
<header>
<div id="info">
<h1>Oyunn.in</h1>
</div>
<div id="categories">
<p>Barbie - Benten - Senten</p>
</div>
<br clear="all"/>
</header>
and css:
header{background-color: #2bd5ec;}
#info{float: left;}
#info h1{font-size: 100%;margin: 0;}
#categories{float: right;}
#categories p{margin:0;}
use overflow:hidden
header{background-color: #2bd5ec; overflow:hidden;}
The overflow CSS property specifies whether to clip content, render scroll bars or display overflow content of a block-level element.
Using the overflow property with a value different than visible, its default, will create a new block formatting context. This is technically necessary as if a float would intersect with the scrolling element it would force to rewrap the content of the scrollable element around intruding floats. The rewrap would happen after each scroll step and would be lead to a far too slow scrolling experience. Note that, by programmatically setting scrollTop to the relevant HTML element, even when overflow has the hidden value an element may need to scroll.
The overflow declaration tells the browser what to do with content that doesn't fit in a box. This assumes the box has a height: if it doesn't, it becomes as high as necessary to contain its contents, and the overflow declaration is useless.
SEE DEMO
Add
header{background-color: #2bd5ec;width:100%; height:30px;}
Background attribute usually needs div's dimensions
actually you didn't clear your child floats so whenever we are using float so we should clear the floats and we can give overflow: hidden; in our parent div to clearing the child floated div's.
header {
background-color: #2BD5EC;
overflow: hidden;
}
see the demo:- http://jsfiddle.net/vE8rd/17/
Let's say we have:
<div id="view-item-hero-info">
<h2>{{name}}</h2>
<h4>{{location}}</h4>
<h3>
<span id="view-item-hero-header-score">
You scored {{userScore}}pts
</span>
</h3>
{{description}}
</div>
Is there a way I can hide the text directly inside #view-item-hero-info? I know I can use text-indent but is there another, nicer, way?
Note: I don't want to hide the element, just everything inside it.
Note 2: Hiding all the elements within #view-item-hero-info is fine, I can use #view-item-hero-info > * { display: none } but then the text directly within #view-item-hero-info is still visible. I need #view-item-hero-info to remain visible so that its background can be seen but the text inside it must be hidden.
You can try:
#view-item-hero-info {
color: transparent;
}
Using this CSS:
visibility: hidden;
hides your element, but preserves the space it would normally take. Whereas this CSS will hide an element as if it never existed:
display: none;
you can use this code if u need hide text
.text-hidden{
font-size: 0;
text-indent: -9999px;
}
to hide all direct child's
use
.hidden-nested > *{
visibility: hidden; /*or next line */
display:none ;
}
if you need all child's use last code but change class to
.hidden-nested *
Use css display property. In HTML this would look like <span style="display: none">
Using javascript: document.getElementById("view-item-hero-header-score").style.display="none"
in css:
#view-item-hero-header-score {
display: none;
}
Using CSS you can set a style:
visibility:hidden
So to hide all descendants (*) within your element:
#view-item-hero-info * { visibility: hidden }
If instead you only want to hide direct descendants ie children but not grandchildren then you use the direct child selector (>)
Rather than selecting all (*) you can select particular descendants eg divs:
#view-item-hero-info div { visibility: hidden }
Equally instead of the visibility you can use:
display:none
The display option doesn't take up space whereas if you want to reserve the space for when the element will be shown you use the visibility option
EDIT:
There isn't a selector just for a text node (ie the text without the element). See Is there a CSS selector for text nodes?. So all children of your span need to be in an element in order to have style applied.
As a hack you could just put another span directly in your main one and all content (including the standalone text) within that. Then the hiding will work.
Could you use JS to iterate though all child items in the elements DOM and then use JS to overwrite the CSS? Something like:
var items_i_want = document.getElementById("view-item-hero-header-score").elements
for(var i = 0; i < items_i_want .length; i++)
{
items_i_want [i].style.display="none"
}