CSS: containing five floated 20% elements with borders - css

I'm trying to align five horizontal menu elements with 'float:left' next to each other inside a container that spans 80% of the screen and a minimum of 960px. For this, I had initially set their min-width to 192px (960/5) and their width to 20%, but quickly realized this does not play well with adding 1px borders, causing one of the buttons to be 'thrown overboard'.
Changing the widths to 19.895333% and 191px, respectively, solved the issue, however this is clearly a hacky solution which also leaves an ugly space of 2-3 pixels at the right side of the menu.
Is there a more elegant way to align these elements and account for the bonus width added by borders, padding etc? I have tried 'overflow:hidden' to simply hide whatever may poke outside the container, but this just hides the entire 5th button.
A picture to illustrate the result:
The html code:
<div class="menucontainer">
<div class="menutab" id="menutab_first">News</div>
<div class="menutab">Game Guide</div>
<div class="menutab">Articles</div>
<div class="menutab">Media</div>
<div class="menutab" id="menutab_last">Community</div>
</div>
The css code:
.menucontainer {
height: 26px;
margin-left: auto;
margin-right: auto;
border-width: 1px;
border-style: solid;
border-color: #303030 #101010 #000 #101010;
border-radius: 0px 0px 8px 8px;
}
.menutab {
line-height: 26px;
float: left;
width: 19.895333%;
text-align: center;
min-width: 191px;
border-right: 1px solid #202020;
background-image: url('../img/menubutton2.png');
background-size: 100% 100%;
font-family: 'Cabin', sans-serif;
}
#menutab_first {
border-radius: 0px 0px 0px 8px;
}
#menutab_last {
border-right: 0px;
width: 20%;
min-width: 192px;
border-radius: 0px 0px 8px 0px;
}
Thank you in advance!

For this you can make use of the box-sizing property to set your borders to appear within your elements rather than outside of them:
elem {
-webkit-box-sizing: border-box; /* Some mobile browsers. */
-moz-box-sizing: border-box; /* Firefox. */
box-sizing: border-box; /* All other browsers IE8+. */
}
border-box
The specified width and height (and respective min/max properties) on this element determine the border box of the element. That is, any padding or border specified on the element is laid out and drawn inside this specified width and height. The content width and height are calculated by subtracting the border and padding widths of the respective sides from the specified ‘width’ and ‘height’ properties.
So in the case of your CSS:
.menutab {
...
width: 20%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
...
}

What you need is box-sizing:border-box;
This CSS property will change the box model for the element such that the border is included inside the width, rather than outside of it as with the standard box model.
This means that your boxes will then be 20% of the width of the page, rather than 20% + the width of the borders.
Problem solved.

box-sizing: border-box causes the width of the borders to be counted as part of the 20%. That's the best solution but if that will interfere with your layout in some way, an alternative is use calc to subtract the borders from the 20%, e.g. width: calc(20% - 2px);

Related

box-sizing: border-box with no declared height/width

I'm trying to understand how box-sizing: border-box work in the code below. When the height or width is set (no padding), it works as intended (border appears inside the div). But if you only use the padding to create the dimension of the div, it does not work. Can someone explain why? Here's the demo:
div.test {
background-color: red;
box-sizing: border-box;
display: inline-block;
border: 5px solid;
text-align: center;
padding: 50px;
vertical-align: middle;
// height: 100px;
// width: 100px;
}
div.test:first-of-type {
border: none;
}
<div class="test">aa</div>
<div class="test">aa</div>
https://codepen.io/anon/pen/bxaBER
TL;DR
An idea is to keep border for both. Instead of none simply make the color transparent so that the size (including border + padding) will always be the same for both.
div.test {
background-color: red;
box-sizing: border-box;
display: inline-block;
border: 5px solid;
text-align: center;
padding: 50px;
}
div.test:first-of-type {
border-color: transparent;
}
<div class="test">aa</div>
<div class="test">aa</div>
Why?
When setting height/width you explictly define that both sould have fixed size and this size will include border, padding and content. As we can read in the documentation:
border-box
tells the browser to account for any border and padding in
the values you specify for an element's width and height. If you set
an element's width to 100 pixels, that 100 pixels will include any
border or padding you added, and the content box will shrink to absorb
that extra width.
And
Here the dimensions of the element are calculated as: width = border +
padding + width of the content, and height = border + padding + height
of the content.
Now, suppose you include a padding of 45px with the 5px border. In this case both box will be equal but you will notice that the one with border will have a height/width 0 for the content because we already reached 100px with padding and border (45px*2 + 5px*2 = 100px) but the other box will still have some space for content:
div.test {
background-color: red;
box-sizing: border-box;
display: inline-block;
border: 5px solid;
text-align: center;
padding: 45px;
height:100px;
width:100px;
vertical-align:middle;
}
div.test:first-of-type {
border:none;
}
<div class="test">aa</div>
<div class="test">aa</div>
Now if we start increasing the padding, the first box still have some content to shrink (10px) but the second one no! In this case, border-box and the fixed width/height will have no effect because border + padding exceeded the 100px (46px*2 + 5px*2 = 102px). That's why starting from 45px of padding we see a difference between both boxes and strating from 50px of padding both box will have no content to shrink BUT the second box has more border which will logically make its size bigger. It also become useless to define width or height.
In other words, border-box only applies when padding + border < width/height because only in this case we still have content to shrink.
Here is a better illustration with bigger border and you will see that we have 3 states. (1) when both have content to shrink (2) when only one has content to shrink (3) when both have no content to shrink:
div.test {
background-color: red;
box-sizing: border-box;
display: inline-block;
vertical-align:top;
border: 30px solid;
text-align: center;
padding: 5px;
width:100px;
height:100px;
animation:pad 10s infinite linear alternate;
}
div.test:first-of-type {
border:none;
}
#keyframes pad {
0% {padding:5px}
33% {padding:20px}
66% {padding:50px}
100% {padding:100px;}
}
.change:after {
content:"";
animation:change 10s infinite linear alternate;
}
#keyframes change {
0%,33% {content:" (1): same size for both and fixed width/height are respected "}
33.1%,66% {content:" (2): The second box has no more content to shrink, it starts growing (fixed height/width and border-box has no effect)"}
66.1%,100% {content:" (3): Both boxes has no more content to shrink, they will keep growing BUT the second one has more border so bigger size"}
}
<p class="change">we are at state </p>
<div class="test">aa</div>
<div class="test">aa</div>
In order to avoid this, we keep the same padding/border for both elements like we initially said.
Assuming this is the only css on the page How wide will the box be when its rendered
.box{ Width: 100px; Height: 50px; Padding: 5px; Border: 1px solid red; Background-color: red;}

3 column layout with inline block not working- the divs aren't lining up correctly

I have a div which contains three child div's, and for some reason the first child div is properly positioned within its parent, but the other two children are positioned lower from the first child. The more content I add to the first child the lower the other children become positioned relative to the top of the container parent.
Heres a jfiddle showing you my problem: http://jsfiddle.net/gY72a/7/
the three children arent on the same line here but you can see the problem when you look at how high the first child is positioned compared to the second one.
Code is already in the jfiddle, but here is the css I am using:
/*Parent div in which all three children are nested*/
#main {
width: 80%;
min-width: 1000px;
background-color: #FFFFFF;
margin: 1% auto;
border-radius: 1px;
border: 0px solid rgba(0, 0, 0, 0.15);
box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.2);
}
/*First child*/
#leftside {
display: inline-block;
width: 18%;
margin: 10px 1% 8px;
padding: 1em;
background-color: rgba(0, 0, 0, 0.1);
}
/*Second Child*/
#innermain {
display: inline-block;
width: 50%;
margin: 10px 1% 8px;
padding:1em;
background-color: #eaeaea;
border-radius: 1px;
border: 0px solid rgba(0, 0, 0, 0.15);
box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.2);
}
/*Third child*/
#rightside {
width: 20%;
min-width: 320px;
padding: 1em 0px;
display: inline-block;
background: #FFFFFF;
margin: 10px 1% 8px ;
border-radius: 1px;
border: 1px solid rgba(0, 0, 0, 0.15);
}
The main problem here is that you are using `display:inline-block" and also that you are using a combination of percentages and margins with ems. Now, theoretically, you could have 3 blocks, and add their widths and the padding, and the margin - to all equal 100, but even if you wanted to go that route, you are using the inline-block method - which by default leaves a little unwanted space between each block, and throws off that number. Beyond that, padding and margins add to the size of the box, so if you have a box that is 20% wide, and has a padding of 1em and a margin of 1% - then it's 20%+2%+2em (+total border width) - and what does that equal? Well, I don't know - and the browser isn't going to love dealing with that either, because depending on window size, that number is going to be different. So, if you want to know the problem, those are the factors leading to the problems.
If you want a solution, then you have a few routes, but they depend on what you need to do. It doesn't appear as though you are building this site responsively. So in that case, you are working with a 1000px wide canvas. - and in that case, then there is no reason why you cant just use px to add up margin/padding/box size etc to equal 100. leave the boxes as display: block; and float them left.
If you want to come into the present, and start using a bit of modern stuff - you should read about box-sizing: border-box - What that does is change the box model so that the padding and borders of boxes moves inside the box and therefore doesn't add to it's size. It's really great and makes working with css a pleasure. Then you don't have to add stuff up to determine the box's size. - so - unless you need to support IE 7 - I would suggest you make it standard in your overall approach to CSS from now on. http://www.paulirish.com/2012/box-sizing-border-box-ftw/
If you are going to float the columns in their "wrapper" thing - then that wrapper thing is no longer going to regognize them in the same way, so you are going to have to look up clearfixing the div, or use overflow:hidden; (which has some issues) or float that wrapper itself to get them to live in the same world again, because floating takes the elements out of the regular flow.
In the case that you can go with box-sizing, then you still have to worry about margins(they don't move inside the box). So, you'll need to have those in percentages, or get another fancy way of making consistent gutter widths, but since you have a static sized site - I'm not going to go into that.
Here is a fiddle without all of your styles - to show how it works.
HTML
<div class="content-wrapper">
<div class="column what">
<h2>What We do</h2>
<p>Bla bla bla</p>
</div>
<div class="column main-content">
<h2>Latest News and Events</h2>
</div>
<div class="column where">
<h2>Where To Find Us</h2>
</div>
</div> <!-- .content-wrapper -->
CSS
*, *:before, *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.content-wrapper {
width: 1000px;
margin-right: auto;
margin-left: auto;
border: 1px solid red;
overflow: hidden; /* should be clearfix instead */
}
.column { /* what the columns have in common */
float: left;
padding: 1em;
}
.what {
width: 25%;
margin-right: 1%;
background-color: orange;
}
.main-content {
width: 48%;
margin-right: 1%;
background-color: yellow;
}
.where {
width: 25%;
background: red;
}
You have specified display:inline-block for the divs below which should align them properly in a row with the widths given. But the width is taken by the content section of the div and the div adds the margins given to them with the width. This is why the blocks are jumping below one another.
When you apply box-sizing: border-box; to the divs, the width of the div will be calculated including the margins given to the corresponding divs.
Hope this helps you.
#main, #leftside, #innermain{
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
}
This should do what you want:
#main div {
float: left;
}

How to add borders to div without messing up the layout?

I have the following elements:
<body>
<div id="container">
<div id="sidebar1"></div>
<div id="content">
<h3>Lorem ipsum</h3>
<p>Whatnot.</p>
</div>
<div id="sidebar2"></div>
</div>
</body>
Following this style:
/* ~~ this fixed width container surrounds all other divs~~ */
#container {
width: 960px;
background-color: #FFF;
margin: 0 auto;
overflow: hidden;
}
#sidebar1 {
float: left;
width: 180px;
/*border: 2px solid black;*/
background-color: #EADCAE;
padding: 0px 0px 100% 0px;
}
#content {
padding: 10px 0;
width: 600px;
float: left;
}
#sidebar2 {
float: left;
width: 180px;
/*border: 2px solid black;*/
background-color: #EADCAE;
padding: 0px 0px 100% 0px;
}
I am trying to achieve this layout: http://jsfiddle.net/QnRe4/
But as soon as I un-comment the borders it turns into this: http://jsfiddle.net/FZxPQ/
** Solved **
The border width was added to each element's total width making them too wide to fit in the container. Removing 2x the border width from each column's width solves the problem: http://jsfiddle.net/FZxPQ/4/
CSS box-sizing to the rescue! This property
alters the default CSS box model used to calculate widths and heights of elements
The border-box value means that
the width and height properties include the padding and border
/* support Firefox, WebKit, Opera and IE8+ */
#container, #sidebar1, #sidebar2 {
box-sizing: border-box;
-moz-box-sizing: border-box;
}
However, browser support is not 100% standardized.
As other answers have already mentioned the extra width which pushes the sidebars out of alignment is because the width calculation includes the border width. box-sizing simply tells the browser that an element with a given width/height should include any border and padding values into the final width/height calculations.
The problem is that when you add in the boarder, the size of the outer divs increased by 4, 2px on each size. So, your container needs to grow in size by 8px.
So change your container to:
#container {
width: 970px;
background-color: #FFF;
margin: 0 auto;
overflow: hidden;
}
See: http://jsfiddle.net/QnRe4/13/
When you apply the borders, that goes outer the divs, so the sidebars will have 184px width which doesn't fits to the container. try addig width: 176px
http://jsfiddle.net/QnRe4/12/
#sidebar1 {
float: left;
width: 176px;
border: 2px solid black;
background-color: #EADCAE;
padding: 0px 0px 100% 0px;
}
Like this? http://jsfiddle.net/QnRe4/3/
What's happening is that your elements are losing their block display properties when you remove the borders.
So, adding display: block to those elements resolves that.
I've also adjusted your element's widths by 4px in width to retain the layout, since removing those borders essentially reduces the space that those elements occupy on-page.

Keeping/scaling DIV Ratio with percentages

At the moment I have a layout that pulls a number of thumbnails into a grid - each is defined by a style that keeps them a fixed ratio, (roughly 16:9) which is defined by pixel dimensions (389px x 230px) but they are looking a bit small on high-res screens.
The images are actually pulled into the DIV as a background that covers 100% width and height of the DIV and then the DIV's obviously control the aspect and size.
What I am looking to do is have these DIV's dynamically resize based on the page size of the device but to keep the ratio of the DIV's.
Is this possible?
My thoughts would be to set the width based on the percentage of the page but then I'm not sure how I would set the height and keep the correct aspect ratio (due to different resolutions etc.)
What would be the best way to do this?
EDIT - Thanks for all your ideas so far, thought maybe I should show you how I'm pulling in the data at the moment.
In my HTML I've got the following code which generated the grid
<a class="griditem" href="../video.php?video=13" style="background-image:url(../video/Relentless/Relentless.jpg); background-size:100% 100%;">
<div class="titles">
<h5>Relentless Short Stories</h5>
<h6>Frank Turner: The Road</h6>
</div>
This is styled with the following CSS
.griditem {
position: relative;
float: left;
margin-right: 17px;
margin-bottom: 17px;
background-color: #777;
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
width: 389px;
height: 230px;
text-align: left;
}
.titles {
padding: 5px;
position: absolute;
bottom: 10px;
left: -1px;
right: -1px;
background: transparent url(../images/layout/white80.png) top left;
-moz-border-radius: 1px 1px 0 0;
border-radius: 1px 1px 0 0;
text-align: left;
}
The reason I'm implementing it this way is so that the Div can float over the bottom of the image.
Just a quick idea which might be useful for you.
It is based on the fact that vertical padding/margin use the WIDTH of the parent box when it is set to percentages, so it is possible to resize a div relative its parent box
http://jsfiddle.net/xExuQ/2/
body,html { height:100%; }
.fixed-ratio-resize {
width: 50%; /* child width = parent width * percent */
padding-bottom: 50%; /* child height = parent width * percent */
height: 0; /* well, it is not perfect :) */
}
​If you want to put some (non-background) content into this nicely resized box, then put an absolutely positioned div inside it.
Reference:
http://www.w3.org/TR/CSS2/box.html#margin-properties and
http://www.w3.org/TR/CSS2/box.html#padding-properties says:
Margins: "The percentage is calculated with respect to the width of the generated box's containing block. Note that this is true for 'margin-top' and 'margin-bottom' as well. If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1."
Paddings:"The percentage is calculated with respect to the width of the generated box's containing block, even for 'padding-top' and 'padding-bottom'. If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1."
EDIT
http://jsfiddle.net/mszBF/6/
HTML:
<a class="griditem" href="#" style="background-image: url(http://pic.jpg);">
<span class="titles">
<span class="name">Unicomp Studios</span>
<span class="title">Springs Buckling (2012)</span>
</span>
</a>
CSS:
.griditem {
float: left;
margin-right: 17px;
margin-bottom: 17px;
min-width: 100px; /* extremely narrow blocks ==> crap looking */
width: 30%;
background: blue no-repeat;
background-size: contain; /* from IE9 only: https://developer.mozilla.org/en/CSS/background-size */
border: 1px solid transparent; /* prevent .titles:margin-top's margin collapse */
}
.titles {
/* <a> elements must only have inline elements like img, span.
divs, headers, etc are forbidden, because some browsers will display a big mess (safari) */
display: block; /* so display those inline elements as blocks */
padding: 5px;
margin: 0 auto;
margin-top: 105%;
background: yellow;
}
.titles > span {
display: block;
}​
I know this might not be the best solution, but
<html>
<style type="text/css">
#cool{
width:40%;
background:blue;
padding-bottom:10%;
}
</style>
<div id="cool" >
</div>
</html>
Here Ive used padding-bottom, to maintain its height relative to its width. U can set padding-bottom as a percentage. Hope this helped.

Pixel Border and Percentage width in Proportion

I think I might already know the answer to this one but I need a sanity check!
Say I have
#gridtest{
width:590px;
}
I could change the width to a percentage by using RESULT=TARGET/CONTEXT. In this case the context is a container with a max-width set to 1000px so I can do this:
#gridtestpercent{
width:59%; /*590/1000*/
}
If I were to shrink the window down the div would always be in the proportion to the its container. But what if I wanted to do
#gridtest{
width:570px;
border:10px solid red;
}
I can work the width out based on the target now being 570 but as the window is shrunk the proportions all go out of sync.
#gridtestpercentnoborder{
width:57%; /*570/1000*/
border:10px solid red;
}
I can't use percentage border. I don't want to use JS to keep checking the context and I can't use the CSS3 box-border declaration yet.
If I wanted to use the technique described in responsive web design by Ethan Marcotte where everything shrinks in relation to each other would I be out of luck if using a border?
Cheers!
You could use CSS3 calc() function,
.selector{
border: 5px solid black;
width: -moz-calc(50% - 10px);
width: -webkit-calc(50% - 10px);
width: calc(50% - 10px);
}
SASS mixin
#mixin calc($property, $expression) {
#{$property}: -moz-calc(#{$expression});
#{$property}: -webkit-calc(#{$expression});
#{$property}: calc(#{$expression});
}
article {
border: 1px solid red;
#include calc( width, '100% - 2px')
}
You could use an inset box-shadow instead of a border:
box-shadow: 0px 0px 0px 10px red inset;
Just pad the inside of the container to compensate.
Edit: I write "pad" but of course if you use padding it'll throw off the box dimensions. Margin the content inside instead.
The accepted answer is not correct. You actually have 2 options:
Use the box-sizing property, so all the paddings and borders are considered part of the size:
.column {
width: 16%;
float: left;
margin: 0 2% 0 2%;
background: #03a8d2;
border: 2px solid black;
padding: 15px;
font-size: 13px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
Or, use the outline property instead of the border property. You will still have problems with the paddings, but it's easier to add. Example:
.column {
width: 16%;
float: left;
margin: 0 2% 0 2%;
background: #03a8d2;
outline: 2px solid black;
}
Full explanation: http://designshack.net/articles/css/beating-borders-the-bane-of-responsive-layout/
Unfortunately, yes, you're out of luck. One hacky way to get around this problem is with a wrapper div that you use to create your border. So the outside div would be 57% (in your example) with a background that is the color of your desired border. Then, the inner div would have a width of 96% or so (play with the exact number to find a border that is appropriate for your design).
If you want to stay semantic you can use div { box-sizing:border-box; } or some absolutely positioned :after elements. See the post How do I add 1px border to a div whose width is a percentage?
In CSS3 you can also use the new box-sizing property to include the pixel and padding count into the width of the element:
box-sizing: border-box;
If possible, depending on your design, what I like to do is put the border as an absolute div with a width of 3px ( for example ) and a height higher than its parent div. I then set overflow hidden on the parent div.

Resources