Position element relative to parent element - css

For example I have fixed nav, is there a way to anchor the list items to the bottom of the nav? I attempted to give the list items a fixed position too but this messes up their layout as you can see at fiddle
here is my code:
#nav {
height: 75px;
width: 100%;
position: fixed;
top: 0;
z-index: 1;
border-bottom: 1px solid white;
background-color: #157FFB;
border-bottom: 2px solid #eeeeee;
}
#nav>ul {
list-style: none;
margin: 0;
}
#nav>ul>li {
display: inline;
/*these two lines were my attempt at anchoring the list items to the bottom f the #nav, but it throws everything out of wack*/
position: fixed;
top: 45px;
}
<div id="nav">
<ul>
<li class="align_left">LOGO</li>
<li class="align_right">Repairs/Upgrades</li>
<li class="align_right">Networking</li>
<li class="align_right">Remote Backups</li>
<li class="align_right">Data Recovery</li>
</ul>
</div>
Any suggestions on how this can be done?

When you use a fixed or absolute position it takes an element out of the flow of the document and hence they stack up on top of each other when you apply those positions to the li elements.
Instead you should be absolutely positioning the ul block to the bottom of the #nav:
#nav > ul {
list-style: none;
margin: 0;
position: absolute;
bottom: 0;
}
#nav > ul>li {
display: inline;
}

As I understand your question, you wish to have the list elements at the bottom of your header. Just change position: fixed; to position: relative;. This keeps the elements flow along with the flow of the page.
Here is your solution:
#nav{
height: 75px;
width: 100%;
position: fixed;
top: 0;
z-index: 1;
border-bottom: 1px solid white;
background-color: #157FFB;
border-bottom: 2px solid #eeeeee;
}
#nav > ul{
list-style: none;
margin: 0;
}
#nav > ul>li{
display:inline;
/*these two lines were my attempt at anchoring the list items to the bottom f the #nav, but it throws everything out of wack*/
position: relative;
top:50px;
}
<div id="nav">
<ul>
<li class="align_left">LOGO</li>
<li class="align_right">Repairs/Upgrades</li>
<li class="align_right">Networking</li>
<li class="align_right">Remote Backups</li>
<li class="align_right">Data Recovery</li>
</ul>
</div>

If you want something to be anchored to the bottom of an element, but still remain in the flow of the page, try using relative positioning. That essentially means you give the #nav element relative positioning, and you give the li elements relative positioning as well:
#nav {
height: 75px;
width: 100%;
position: relative;
top: 0;
z-index: 1;
border-bottom: 1px solid white;
background-color: #157FFB;
border-bottom: 2px solid #eeeeee;
}
#nav>ul {
list-style: none;
margin: 0;
}
#nav ul li {
display: inline;
position: relative;
top: 45px;
}
<div id="nav">
<ul>
<li class="align_left">LOGO</li>
<li class="align_right">Repairs/Upgrades</li>
<li class="align_right">Networking</li>
<li class="align_right">Remote Backups</li>
<li class="align_right">Data Recovery</li>
</ul>
</div>
This seems to work pretty well, please tell me if it doesn't.
The problem you encountered was that fixed positioning put them all in a mess. Fixed positioning positions ALL the items relative to the viewport, so if you had all the lis with
position: fixed;
top: 45px;
They would all go in the same spot.

Related

Align item left, or right if no room left in window

How can you display an item per default in its "normal" position (preferably over any following items), like this:
div {
border: 1px solid black;
}
ul {
display: flex;
padding: 0;
list-style: none;
width: 250px;
border: 1px solid black;
}
li {
display: flex;
position: relative;
}
.item {
padding: 0.4em;
background-color: #f99;
}
.dropdown {
position: absolute;
left: 100%;
z-index: 1;
padding: 0.4em;
opacity: 0.7;
background-color: #2f6f44;
}
<ul>
<li>
<div class="item">First</div>
</li>
<li>
<div class="item">Second</div>
<div class="dropdown">Dropdown</div>
</li>
<li>
<div class="item">Third</div>
</li>
<li>
<div class="item">Fourth</div>
</li>
</ul>
but if the window becomes too small (represented by the ul here), it sticks to the right:
div {
border: 1px solid black;
}
ul {
display: flex;
position: relative;
padding: 0;
list-style: none;
width: 150px;
border: 1px solid black;
}
li {
display: flex;
}
.item {
padding: 0.4em;
background-color: #f99;
}
.dropdown {
position: absolute;
right: 0;
z-index: 1;
padding: 0.4em;
opacity: 0.7;
background-color: #2f6f44;
}
<ul>
<li>
<div class="item">First</div>
</li>
<li>
<div class="item">Second</div>
<div class="dropdown">Dropdown</div>
</li>
<li>
<div class="item">Third</div>
</li>
<li>
<div class="item">Fourth</div>
</li>
</ul>
In other words, if (this.left + this.width > totalWidth) stick right else stay left.
I can either get one or the other behaviour (like above), but not so that it switches seamlessly between the two.
The simplest solution is to compute the element width and the window width and position it using JavaScript, but bugs/edge cases easily slip in, so I'm trying to look for a complete CSS solution.
Any number of containers/wrappers are welcome. One solution I tried looking at was wrapping all the "following" elements (Third and Fourth in the examples above) in a separate li with Dropdown. That way a flex element can take up the space between the previous element (Second) and the edge of the container, but then Dropdown can't go any further left than Second (if the container gets too small).
The elements are dynamic in width based upon changing content.

Overflow auto on unknown children height

I have an element (on which I know the width & height, I can't remove the height) with some elements inside. I've simplified it in the snippet so I just have a title (with unknown length) and a list.
I need the list (only the list, not the whole container) to be overflow: auto but I can't figure it out since I don't know its height and I can't use flexbox (IE9+ :/).
I want to avoid using JavaScript for this (I can do it in JavaScript but I really don't want a FOUC).
div {
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
height: 400px;
}
h1 {
margin-top: 0;
border: 1px dashed red;
}
ul {
margin: 0;
padding: 0;
overflow: auto;
}
li {
display: block;
padding: 5px 0;
border-top: 1px solid;
}
<div>
<h1 contenteditable>
My long title that can be on multiple lines
</h1>
<ul>
<li>a list</li>
<li>of element</li>
<li>that can</li>
<li>be long</li>
<li>that should</li>
<li>overflow auto</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
</ul>
</div>
You cannot make the height of both dynamic, without something like JavaScript.
For one to overflow, it needs a reference. Why would the list overflow but not the header for example?
You can go set the list position to absolute, but then you need coordinates for top and bottom, which you won't have because in CSS you can't get that from other element (the header).
Without something like flex, you other option is JS I think.
You can render the header and list with visibility hidden (not display block, so their dimentions can be calculated), and remove that once you apply your JS for minimal FLOC effect.
just add overflow-y: auto; to your container element
.wrapper {
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
height: auto;
display: inline-block;
}
h1 {
margin-top: 0;
border: 1px dashed red;
float: left;
}
.container {
overflow-y: auto;
height: 300px;
width: 100%;
float: left;
}
ul {
margin: 0;
padding: 0;
overflow: auto;
}
li {
display: block;
padding: 5px 0;
border-top: 1px solid;
word-break: break-word;
}
<div class="wrapper">
<h1 contenteditable>
My long title that can be on multiple lines
</h1>
<div class="container">
<ul>
<li>a list</li>
<li>of element</li>
<li>that can</li>
<li>be long</li>
<li>that should</li>
<li>overflow auto</li>
<li>blaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
</ul>
<div>
</div>
If you can't use flexbox, use CSS tables:
Set the height of the table
Set height: 0 to the title cell to make it be only as tall as required by its contents.
Wrap the ul inside a table-row, which will take the remaining space left by the title.
Take the ul out-of-flow (to avoid circular definitions) and make it have the same sizes as that wrapper.
#container {
display: table;
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
height: 400px;
}
#container > h1 {
display: table-cell;
height: 0;
margin-top: 0;
border: 1px dashed red;
}
#container > div {
display: table-row;
position: relative;
}
#container ul {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: 0;
padding: 0;
overflow: auto;
}
li {
display: block;
padding: 5px 0;
border-top: 1px solid;
}
<div id="container">
<h1 contenteditable>
My long title that can be on multiple lines
</h1>
<div>
<ul>
<li>a list</li>
<li>of element</li>
<li>that can</li>
<li>be long</li>
<li>that should</li>
<li>overflow auto</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
<li>bla</li>
</ul>
</div>
</div>
Here my JS solution for now, I'd like to have it in CSS if possible but it's working in the meantime:
const height = container.clientHeight - list.offsetTop
list.style.height = height + 'px'
There are couple of ways to do it
First would be just remove the height prop on div.
If you don't want to do so.. you can either choose to cut (overflow:hidden) or scroll overflow:scroll the list
ie, you div styling can be:
div {
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
height: 400px;
overflow: scroll; /* or hidden */
}
or just
div {
margin: 20px;
padding: 15px;
border: 1px solid;
width: 200px;
}
EDIT:If you dont want the whole container to overflow (as said in comments) just add max-hight to ul
your ul styling would be something like:
ul {
margin: 0;
padding: 0;
max-height: 100px; /*or anything you think appropriate */
overflow: auto;
}
and rest of the css can be same as in OP.

CSS positioning and scrolling

I am trying to get a left menu and a right banner and have them stay fixed in place when the centre panel scrolls text - the banner will have to be on top of the centre panel due to size - the colour scheme is white text on black background except for the menu which is an <ul> with its own colour scheme
I am rather new to css so may have already made a prat of myself - I have tried but currently the top right banner does stay fixed when scrolling but the text overlays it and the top left menu shoots off the screen
JS Fiddle
<head>
<style>
#container {
width:90%;
height 100%;
background-color:Black;
margin: 0 auto;
text- align: left;
}
#banner {
float: right;
background-color:black;
width:40%;
top:1;
right:1;
position:fixed
}
#sidebarmenu {
float: left;
width: 10%;
background-color:Black;
padding: 15px 10px 15px 20px;
top:1;
left:1;
position:fixed
}
#mainContent {
background-color: Black;
color:White;
position: absolute;
left: 120px;
width: 50%;
top:220;
margin: 0 0 0 15%;
}
body {
color: white;
background-color: black;
}
.sidebarmenu ul {
margin: 0;
padding: 0;
list-style-type: none;
font: bold 13px Verdana;
width: 180px;
border-bottom: 1px solid #ccc;
}
.sidebarmenu ul li a {
display: block;
overflow: auto;
color: black;
text-decoration: none;
padding: 6px;
border-bottom: 1px solid #778;
border-right: 1px solid #778;
}
.sidebarmenu ul li a:link, .sidebarmenu ul li a:visited, .sidebarmenu ul li a:active {
background-color: #c0c0c0;
}
.sidebarmenu ul li a:visited {
color: white;
}
.sidebarmenu ul li a:hover {
background-color: black;
color:red;
}
</style>
</head>
<body>
<div id="container">
<div id="banner" ><img style="float:right" alt="logo text" src="/banner.png" /></div>
<div id="mainContent" >TEXT</div>
<div class="sidebarmenu">
<ul id="sidebarmenu1">
<li>Home</li>
<li>Info</li>
<li>Contact Us</li>
<li>Page 2</li>
<li>Page 3</li>
<li>Page 4</li>
<li>Page 5</li>
<li>Page 6</li>
</ul>
</div>
</div>
</body>
any help /comments / guidance on what I should be learning /looking at is appreciated
Phew! Where to start? lol Your code needed to be fixed pretty much on every line. I have a reworked demo here but basically, you must pay attention to site architecture when you are positioning elements. Organization is everything is front end development.
See DEMO
First of all, once you start using position: absolute; or position: fixed;, using float and margin becomes irrelevant.
Also, when using top: x;, left: x;, right: x;, or bottom: x; always make sure to add a size unit to your value, i.e. top:1; should be top: 1px;
If I understood correctly from the css you posted, something that'll get you closer to what you want to achieve is this:
html,body{ margin: 0; padding: 0; color: #fff; background: #000; height: 100%; width: 100%; overflow: hidden; }
#container { width:100%; height: 100%; text-align: left; overflow: auto; border: 1px red solid;}
#mainContent { width: 90%; color: #fff; margin: 0 auto; }
#banner { background-color: #000; width:40%; top:1px; right:1px; position:fixed; }
#sidebarmenu { width: 10%; background: #000; padding: 15px 10px 15px 20px;top:1px;left:1px;position:fixed; }
Take a look at this jsfiddle I made to see what this css does: http://jsfiddle.net/beYuC/
NOTE: You might have noticed I made the html and body have a height of 100%. This is because unless you set a height for the html and body, any other element on the page you want to make 100% will simply be flattened out.
NOTE 2: Be sure to check out this website and its CSS for an example of a well done content container and sidebar menu with 100% height: http://www.jlescure.com/

CSS :hover to affect 2 elements

So I have some CSS generating this.
The HTML code as follows.
<div class="menu">
<ul>
<li><a href='index.html'>Home</a></li>
<div class="menutab"></div>
<li><a href='about_us.html'>About Us</a></li>
<div class="menutab"></div>
<li><a href='#'>Order Online</a></li>
<div class="menutab"></div>
<li><a href='gallery.html'>Gallery</a></li>
<div class="menutab"></div>
<li><a href='#'>Contact Us</a></li>
<div class="menutab"></div>
</ul>
</div>
And the CSS
.menu {
width: 100%;
height: 220px;
float: left;
margin-left: -20px;
position: relative;
text-align: center;
}
.menu li{
display: block;
list-style: none;
width: 100%;
background: #EBE5D9;
height: 50px;
margin-left: -40px;
margin-top: 5px;
line-height: 50px;
}
.menu li:hover {
background: #AEC32A;
}
.menu li a{
text-decoration: none;
font-size: 20px;
color: #000000;
font-family: fantasy;
}
.menutab {
width: 30px;
position: relative;
margin-top: -3px;
margin-left: -71px;
border-right: 21px solid #EBE5D9;
border-bottom: 21px solid transparent;
}
Basically what I am wanting is for the hover effect to turn the whole thing green, currently .menu li:hover turns the block the colour #AEC32A but I also want it to turn the .menutab border the same colour, anyway of doing this? preferably without using Javascript.
Thanks in advance for your help :-)
Try the adjacent selector.
.menu li:hover+.menutab {
border-right-color: #AEC32A;
}
JS Bin Demo
This is no problem with the adjacent sibling combinator.
Simply add this to your css:
.menu li:hover + .menutab{
border-right-color: #AEC32A;
}
This selects the immediately preceeding element (.menutab) of the first element (.menu li:hover).
see the live demo
Browser-support is 100% if you don't care for old IEs <(=) 8;)

Fluid layout with even width navigation items

I'm building a site for mobile devices and therefore has a fluid layout.
My navigation list looks like this:
<ul>
<li>home</li>
<li>about</li>
<li>work</li>
<li>contact</li>
</ul>
Problem is, the first list item needs to be 100px only (left aligned always), and the other 3 split evenly, therefore is it possible to have even width for all list items except for the first one (without using javascript).
This is the simplest way I could think of:
ul { overflow: hidden; padding-left: 100px; position: relative; }
li { width: 33.33%; float: left; }
li:first-child { position: absolute; top: 0; left: 0; width: 100px; }
The main idea is taking the first li out of the flow (position: absolute) and adding a padding-left to the ul (space for the first li). Now if we set the percentage width for the other lis, they will take up the remaining space.
And here is a jsFiddle Demo. I added a red border on the ul which shows that because of the percentages lis will not accurately fill it.
I am unsure what mobile browsers you want to support, but except :first-child (which can be worked around by adding a class on the first list item) I assume they must support everything I used.
hmm a bit cludgy - but this seems to work, it does require nesting the list (second 3 links in separate list) and a span for the "home" link, theory is that you need the first link to float, width: 100px, then you need the second group not to float and have their overflow hidden so the group take up the remaining space.. then you float the 3 links # 33% inside the non-floated container
Example : HERE
CSS:
div {
width: 90%;
margin: 0 auto;
}
ul {
margin: 0; padding: 0; list-style: none; /* reset */
float: left;
width: 100%;
}
li {
float: left;
width: 100%;
text-align: center;
}
li span {
float: left;
width: 99px;
background: #eee;
border-right: 1px solid #000;
}
ul ul {
float: none;
overflow: hidden;
width: auto;
}
li li {
width: 33%;
background: #ffe;
border-right: 1px solid #000;
}
HTML:
<div>
<ul>
<li><span>home</span>
<ul>
<li>about</li>
<li>work</li>
<li>contact</li>
</ul>
</li>
</ul>
</div>
For what it's worth, this was what I was thinking of when I made my comment on your question:
http://jsfiddle.net/4t9fV/
ul {
display: table;
width: 100%;
background: #ccc;
table-layout: fixed
}
li {
display: table-cell;
text-align: center;
outline: 1px dashed red
}
li:first-child {
width: 100px
}

Resources