Adjust child size based on number of children - css

I want to make a UI that is similar to tabs in a browser.
To this end, I have elements with this CSS:
width: 20%;
max-width: 150px;
Nice and simple, responsive and awesome.
Only supports five tabs, though. If I want to support 10 tabs, it's as easy as changing to width: 10%.
So basically, I want something like:
width: calc(100% / number-of-children)
If such a thing were possible, that'd be amazing.
I'm currently just using JavaScript to set the width to the above expression. Simple, functional, but I figured I'd ask if anyone knows of a CSS-only solution.

with CSS3 you may use display: flex. E.g.
markup
<section>
<div>tab 1</div>
<div>tab 2</div>
<div>tab 3</div>
<div>tab 4</div>
</section>
Css
section {
display: flex;
}
div {
flex-grow: 1;
max-width: 150px;
}
Codepen example: http://codepen.io/anon/pen/EGbpH/

display: table is your friend.
ul {
display: table;
width: 100%;
}
li {
display: table-cell;
}
Demo

In CSS3 there's a function called calc() so you can use
width: calc(100% / 10);
Here you can find documentation and which browser support it ;)

Related

CSS column layout with last elements' heights set equally

I have a 3-column layout which I'm trying to show you with this paint illustration.
I want the last divs of each column to take up the remaining space (blue).
The overall height of this layout is not fix, nor the number of divs.
Some of the divs will have fix dimensions, others don't.
Is there a pure CSS solution for this?
The cleanest way to achieve this is to use CSS flexible boxes:
<div class="col1"> ... </div>
<div class="col2"> ... </div>
<div class="col3"> ... </div>
CSS:
body{
display: -ms-flexbox; /* ie 10 (older but working flex implementation) */
display: -webkit-flexbox;
display: flex;
min-height: 100vh; /* optional, forces minimum height to 100% of viewport */
margin: 0;
padding:0;
}
.col1, .col3{
width: 25%;
}
.col2 {
width: 50%;
}
(demo)
The markup is simple, CSS is easy to understand, no "hacks". The only disadvantage right now is the poor browser support (IE 10+). I wouldn't consider it a big one, because you can work around this in IE 9- by using javascript.
Check out "Solved by flexbox" for other uses cases.
Another good solution that I have been using for years is the "The Perfect 3 Column Liquid Layout". The CSS is clean, but a little harder to understand and HTML is a little bulky because it requires wrapper elements for each column. If you need IE 6+ support without resorting to javascript, this is probably the 2nd best choice.
There are other ways to do this:
Table layout (display:table and related properties)
Background images on the body (for solid colors CSS gradients work too)
They are explained in this article (ignore the flex box one, because it uses the old implementation with some unnecessary 99999px margin hack).
But these introduce other limitations that can outweigh the ones from the first two methods. For example, Firefox not positioning absolute elements relative to the table cell. With backgrounds this kind of positioning is not possible at all, because the columns don't have real 100% height
Susy might do the trick for you.
It lets you easily make responsive grids in Sass which isn't vanilla css but will compile down to it. Square Market uses susy and if you take a look at their home page, linked previously and included below, they accomplish a similar effect to what your looking for.
Heres a basic example of a responsive grid so you can get a feel for how easy it is:
// Complex AG grid, brought to you by Susy:
.ag1 { #include span-columns(2,10); }
.ag2 { #include span-columns(6,10); }
.ag3 { #include span-columns(2 omega, 10); }
.ag4 { #include span-columns(3,6); }
.ag5 { #include span-columns(3 omega,6); }
.ag6 { #include span-columns(2,6); }
.ag7 { #include span-columns(4 omega,6); }
.ag8 { #include span-columns(2,4); }
.ag9 { #include span-columns(2 omega,4); }
.ag10 { clear: both; }
Like you want, you dont have to specify the overall height of a particular column and can lock the dimensions of a particular column in.
This can be achieved with a combination of CSS Grid and Flexbox:
html,
body {
height: 100%;
}
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
border: solid 2px gray;
padding: 12px;
height: 100%;
grid-gap: 10px;
min-height: 450px;
}
.column {
display: flex;
flex-flow: column;
}
.item {
border: solid 2px orangered;
height: 100%;
margin: 5px 0;
}
.item.fixed1 {
height: 100px;
}
.item.fixed2 {
height: 380px;
}
<div class="grid">
<div class="column">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item fixed1"></div>
<div class="item"></div>
</div>
<div class="column">
<div class="item fixed2"></div>
<div class="item"></div>
</div>

max-width:-webkit-fit-content ie 8 equivalent?

Are there any hacks for max-width:-webkit-fit-content; for ie 8?
Trying to get a child div to not take up the whole width of the parent and this works well with ff, chrome and safari; hoping there's some hack to get it to work with ie 8 as well.
Fiddle showing the behavior: http://jsfiddle.net/XtZq9/
Code for the behavior I want in ie8:
#wrap {
background-color: aqua;
width:300px;
height: 50px;
padding-top: 1px;
}
.textbox {
background-color: yellow;
max-width: intrinsic;
max-width:-webkit-fit-content;
max-width: -moz-max-content;
margin-top: 2px;
}
<div id="wrap">
<div class="textbox">
Here is some text
</div>
<div class="textbox">
Here is other, longer, text
</div>
</div>
From demosthenes.info, I learned I can simply use
display: table;
instead of
width: fit-content;
Check the link however about problems with whitespaces. It does not apply to my case, and simply replacing width: fit-content with display: table solved my problem quite easily.
The closest I can think of is floating your elements. Not exactly alike, but probably sufficiently alike;) You need to set extra margin though, but this should be no problem with a conditional stylesheet.
.textbox {
background-color: yellow;
float:left;
clear:left;
}
Your modified fiddle
It might depends on the situation:
I had a block-level element with width: fit-content;. As this doesn't work on IE, the element was taking the full available width (as expected).
But I wanted it to just adjust its size to its content.
Finally, i fixed it with:
display: inline-flex;
Not yet; keep watching http://caniuse.com/#feat=intrinsic-width &
https://wpdev.uservoice.com/forums/257854-internet-explorer-platform/suggestions/6263702-css-intrinsic-sizing

How to float an element left with full height of the wrapper?

HTML:
<div class="wrapper">
<div class="left">
Foo
</div>
<div class="right">
Text row 1
</div>
</div>
<div class="wrapper">
<div class="left">
Foo Bar
</div>
<div class="right">
Text row 1<br>
Text row 2<br>
Text row 3
</div>
</div>
CSS:
.wrapper {
overflow:hidden;
}
.left {
width:80px;
float:left;
height:100%;
}
How can I give the floating div the full height of the wrapper (whose height is varying)?
is it possible without jQuery?
Test: http://jsfiddle.net/Q6B43/
The display: table solution
Within tables each cell of a row has the same height.
.wrapper {
display: table;
width: 100%;
}
.left, .right {
display: table-cell;
}
This is the best solution in my opinion, but is not compatible before IE8.
Here is the Fiddle for this solution.
Using absolute positioning
Absolute positioned elements respect their relative parents height:
.wrapper {
position: relative;
padding-left: 85px;
}
.left {
position: absolute;
left: 0;
top: 0;
}
Normally I would not recommend absolute positioning in most situations. But as you have a fixed width anyway, maybe it does not matter. But be aware of the fact that this will ignore long contents in .left. The height is just controlled by .right.
Here is an update to your Fiddle.
The flexible solution
This is so new I would not recommend using it right now, but just to be complete. You could use CSS3 flex, but be aware of browser compatibility:
.wrapper {
display: flex;
}
The Fiddle (tested in current Chrome and Firefox).
The grid layout
Even newer than flexbox, CSS grid seams to be the perfect answer for layout questions.
.wrapper {
display: grid;
grid-template-areas: 'left right';
}
.left {
grid-area: left;
}
.right {
grid-area: right;
}
Browser compatibility is rare, if you go back a view versions. Besides, it would be overkill for the OP's scenario in my opinion, but for more complex layout troubles in the future, this is a very powerful thing.
See it in the Fiddle.
Add:
body, html { height:100% }
And give your wrapper a fixed height in pixels.

Fixed width columns with fluid gutters

I know this can be done with columns, but I have to support IE.
I'm trying to get to a layout whose columns are all fixed width, with the gutters being fluid.
I couldn't get this to work with floats, so I settled on using justified inline-block items:
HTML
<div class="wrapper">
<div></div>
<div></div>
<div></div>
<!-- more divs... -->
</div>
CSS
.wrapper {
text-align: justify;
}
.wrapper div {
width: 100px;
display: inline-block;
}
This works wonderfully, but the last row of divs are all aligned to the left: http://jsfiddle.net/EsHh3/
The only solution I found is to add additional unnecessary divs: http://jsfiddle.net/EsHh3/1/
I feel uncomfortable about this, so I'd like to know if there are any other options.
Please don't tell me not to re-invent the wheel. I have not found any fluid grid system that supports fluid gutters.
For what you want to do, I'm afraid a CSS only solution is not available at the moment, much less if you want it to work in IE8.
Since you want to have (a) items that are in the HTML source as a list (b) a variable number of columns depending on available space (c) column spacing depending on width of container I think the solution you'll need would have to employ at least a bit of javascript.
Consider on of the frameworks proposed in the other answers. One I've worked with and could do what you want is Masonry (or the for-pay bigger brother Isotope). (There's also a non-jQuery version of Masonry). You'll have to come up with a function that when the page is resized, recalculates the desired gutter and reconfigures the framework. Something along the lines of calculating x = how many items would fit per line based on the container width and item width and then dividing the remaining space by x-1.
If you want to stick with the idea of adding extra DIV's to the markup, an alternative would be to listen to resize events, and add DIVs as needed based on the width and how many items would fit per line.
ORIGINAL ANSWER, which failed to fit all the criteria.
Since you're relying on text-align: justified the reason the last line doesn't expand to the full width is because there's no line break at the end of it. So to accomplish that we add an extra element with an wrapper:after {} rule, that is also an inline block with a width of 100% so it guaranties a line break.
See fiddle
The CSS ends up something like:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
}
.wrapper div {
width: 100px;
display: inline-block;
}
.wrapper:after {content: ''; width: 100%; display: inline-block; background: pink; height: 2px; overflow: hidden}
Note that the pink background is there so that you can see where the element is. You might need to play with the border/margin/padding of that extra element or the wrapper so that content that comes after wrapper doesn't gain extra margin. In chrome unfortunately there's a slight missalignment of the last row items, possibly because of the extra space between the last DIV and the fake element.
Hey I don't know why you want a fluid gutter, but I have a simple grid sample which you might want to have a look and if you want to see the css then click the SCSS on the codepen site. Also, if you are learning then this sample is very good start point for how to make your own grid. Also, to avoid yourself reinventing the wheel you might want to try different grid frameworks out there. Just google css grid frameworks.
you can try this:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
moz-column-count: 3;
-moz-column-gap: 20px;
-webkit-column-count: 3;
-webkit-column-gap: 20px;
column-count: 3;
column-gap: 20px;
}
Updated URL
This is how I would go about it: http://codepen.io/jeremychurch/pen/wmtJz
.container {
display: table;
width: 100%; }
.cell {
display: table-cell; }
.content {
width: 15em;
margin: 0 auto; }
<div class="container">
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
</div>

How do I align spans or divs horizontally?

My only problem is making them line up three-across and have equal spacing. Apparently, spans can not have width and divs (and spans with display:block) don't appear horizontally next to each other. Suggestions?
<div style='width:30%; text-align:center; float:left; clear:both;'> Is what I have now.
You can use divs with the float: left; attribute which will make them appear horizontally next to each other, but then you may need to use clearing on the following elements to make sure they don't overlap.
You can use
.floatybox {
display: inline-block;
width: 123px;
}
If you only need to support browsers that have support for inline blocks. Inline blocks can have width, but are inline, like button elements.
Oh, and you might wnat to add vertical-align: top on the elements to make sure things line up
My answer:
<style>
#whatever div {
display: inline;
margin: 0 1em 0 1em;
width: 30%;
}
</style>
<div id="whatever">
<div>content</div>
<div>content</div>
<div>content</div>
</div>
Why?
Technically, a Span is an inline element, however it can have width, you just need to set their display property to block first. However, in this context, a div is probably more appropriate, as I'm guessing you want to fill these divs with content.
One thing you definitely don't want to do is have clear:both set on the divs. Setting it like that will mean that the browser will not allow any elements to sit on the same line as them. The result, your elements will stack up.
Note, the use of display:inline. This deals with the ie6 margin-doubling bug. You could tackle this in other ways if necessary, for example conditional stylesheets.
I've added a wrapper (#whatever) as I'm guessing these won't be the only elements on page, so you'll almost certainly need to segregate them from the other page elements.
Anyway, I hope that's helpful.
you can do:
<div style="float: left;"></div>
or
<div style="display: inline;"></div>
Either one will cause the divs to tile horizontally.
I would do it something like this as it gives you 3 even sized columns, even spacing and (even) scales. Note: This is not tested so it might need tweaking for older browsers.
<style>
html, body {
margin: 0;
padding: 0;
}
.content {
float: left;
width: 30%;
border:none;
}
.rightcontent {
float: right;
width: 30%;
border:none
}
.hspacer {
width:5%;
float:left;
}
.clear {
clear:both;
}
</style>
<div class="content">content</div>
<div class="hspacer"> </div>
<div class="content">content</div>
<div class="hspacer"> </div>
<div class="rightcontent">content</div>
<div class="clear"></div>
I would use:
<style>
.all {
display: table;
}
.maincontent {
float: left;
width: 60%;
}
.sidebox {
float: right;
width: 30%;
}
<div class="all">
<div class="maincontent">
MainContent
</div>
<div class="sidebox">
SideboxContent
</div>
</div>
It's the first time I use this 'code tool' from overflow... but shoul do it by now...
What you might like to do is look up CSS grid based layouts. This layout method involves specifying some CSS classes to align the page contents to a grid structure. It's more closely related to print-bsed layout than web-based, but it's a technique used on a lot of websites to layout the content into a structure without having to resort to tables.
Try this for starters from Smashing Magazine.
Look at the css Float property. http://w3schools.com/css/pr_class_float.asp
It works with block elements like div. Alternatively, what are you trying to display, tables aren't evil if you're really trying to show a table of some information.
I would try to give them all display: block; attribute and using float: left;.
You can then set width and/or height as you like. You can even specify some vertical-alignment rules.
<!-- CSS -->
<style rel="stylesheet" type="text/css">
.all { display: table; }
.menu { float: left; width: 30%; }
.content { margin-left: 35%; }
</style>
<!-- HTML -->
<div class="all">
<div class="menu">Menu</div>
<div class="content">Content</div>
</div>
another...
try to use float: left; or right;, change the width for other values... it shoul work... also note that the 10% that arent used by the div its betwen them... sorry for bad english :)

Resources