How to align 'n' divs horizontally WITH margin/padding? - css

I have the following HTML:
<div class="top_buttons">
<div class="top_button">
<img src="img/image1.png">
</div>
<div class="top_button">
<a href="#">
<img src="img/image2.png">
</a>
</div>
<div class="top_button">
<a href="#">
<img src="img/image3.png">
</a>
</div>
</div>
And the following CSS which works perfectly:
.top_buttons{
width: 100%;
height: auto;
margin: 0 auto;
overflow: hidden;
}
.top_button{
float: left;
width: 33.333%;/*Because I have 3 images with the same width, I want each to have 1/3 of the total width space available (mobile website)*/
}
The problem comes when I want to add some margin and/or padding to the inner divs (that is, the parents of the images). If I add a border/padding/margin to those divs, the above 33.333% I set will not work anymore as obviously each "top_button" div will contain not only the image, but the border/padding/margin added to the div too.
So, my temporary solution was to decrease that percentage to something like 31%. However, depending on the cell phone, more or less pixels will be left in the right side of the screen, as I am just trying to guess the length that the div will have with the extra border/padding/margin in terms of percentage. What I want is a solution that I can still use 33.333% even if I set borders/padding/margins to the inner divs, so I can have a pixel perfect horizontal alignment.
In short, how can I align 'n' divs horizontally knowing that the divs will have border/padding/margin too and that I do not know the total width of the "top_button*s*" div (because the width of the display varies depending on the phone screen).

Use box-sizing. Box-sizing allows you to add padding and border without worrying about breaking the width. However, margin will still break the alignment. In order to account for margin you need to subtract the amount of margin from the width of the element.
.top_button{
float: left;
width: 33.333%;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}

The current standard box-model behavior is what you described in your question. If you define a width it doesn't mean the element will only be as wide as the width-value. Instead padding, etc. get added to it.
To achieve the more intuitive behavior you need the an alternate box-model. Now if you define width you're really defininf the width with all possible paddings, borders and so on.
The following CSS is exactly what you need for this. Note that this CSS will enable the alternate box model for all elements. You may also just define them for your needed elements, although you than have to mess with two different approaches in one project.
*, ::before, ::after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}

If you run into cross-browser compatability problems with box-sizing, here's an alternative. It requires an additional "inner" div for each button, to which you can apply your margins.
HTML:
<div class="top_button">
<div class="top_button_contents">
<a href="#">
<img src="img/image2.png" /> some button text for testing
</a>
</div>
</div>
CSS:
.top_button {
float: left;
width: 33.333%;
}
.top_button .top_button_contents {
position:relative;
margin:0px 10px 0px 0px;
background-color:#CCC;
}
.top_button.last .top_button_contents {
margin:0px;
}
Here is a jFiddle.

Related

Making <img> responsive when within <a>tag?

I have been using the following css to make my images responsive
img{
max-width: 100%;
height: auto;
}
However it doesn't seem to work when the img is within an <a> tag ie.
<img class="fbicon" src="images/fbicon.png" alt="main">
Why is this and what could be a way around it?
Here is the complete code - (it is responsive on the fiddle but not on the site):
https://jsfiddle.net/bLchqb9u/
use width insted of max-width , find the working fiddel : https://jsfiddle.net/5n4rarrL/
The 100% always applies to the value of the parent element. By default <a> doesn't have a 100% width (it's would just be as big as it's content). You would have to change the behaviour, like this:
<img class="fbicon" src="images/fbicon.png" alt="main">
Demo here:
<div style="width: 300px">
<a href="#" style="max-width:100%">
<img style="width:100%;" src="https://upload.wikimedia.org/wikipedia/commons/1/17/Gustave_Caillebotte_-_Paris_Street%3B_Rainy_Day_-_Google_Art_Project.jpg" alt="main">
</a>
</div>
A percentage in max-width is resolved with respect to the width of the containing block.
Then, the only case where your code may not work is
If the containing block's width depends on this element's width, then
the resulting layout is undefined in CSS 2.1.
That should only happen when the width of the containing block is calculated with the shrink-to-fit algorithm. For example, floats, absolutely positioned or inline-blocks with width: auto.
div {
float: left; /* Shrink-to-fit width, depends on the content */
}
img {
max-width: 100%; /* Depends on the containing block */
height: auto;
}
<div>
<a href="#">
<img src="http://lorempixel.com/1000/200/" />
</a>
</div>
The solution is preventing the containing flock from depending on the content. Make sure it has an explicit width.
div {
float: left;
width: 100%; /* No longer depends on the content */
}
img {
max-width: 100%; /* Depends on the containing block */
height: auto;
}
<div>
<a href="#">
<img src="http://lorempixel.com/1000/200/">
</a>
</div>
You should make the <a> element a block container.
Like this:
a {
display: block;
}
img{
width: 100%;
height: auto;
}
<img class="fbicon" src="https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia-logo-v2_1x.png" alt="main">
This way the <a> tag will behave as a container and the image will stretch to the size of that.
Tried display and width suggestions, but still the the images were not responsive for some reason (while another img was), even though it worked on jfiddle. Finally, the new srcset came to the rescue,
<img class="fbicon" src="images/fbiconlarge.png"
srcset="images/fbiconlarge.png 1380w,
images/fbiconlarge.png 640w,
images/fbiconlarge.png 320w"
However must say, now its a bit too responsive - ending up too small on the smallest screen. Will post a separate Q. THanks #Oriol, Hasan, Hans, CodeiSir

Vertically centre variable-length content inside responsive boxes with fixed-pixel margins?

I'm looking for the simplest way to achieve a type of layout that looks simple:
...but actually involves a lot of criteria, many of which involve non-trivial CSS issues:
Vertically centred content in a div...
...where the content is of variable length (so distance from top and bottom can't be hard coded)...
...where the div is inside a selection of floated divs...
...where those divs have percentage widths to fill the screen on a responsive layout...
...where there is a fixed pixel gap between each div...
...where the divs have solid background colours or images and the background behind the divs isn't a known solid colour that can be re-applied
Various elements of this have been addressed in separate questions (for example vertically aligning floated divs, and pixel gaps between responsive percentage-width divs), but I couldn't find anything combining them.
Simplest means:
As few HTML wrappers as possible
Minimal extra Javascript (none if possible)
Minimal CSS that needs to change when breakpoints change the number of divs on each row
Minimal code, quirks, or fragile CSS trickery (e.g. relying on browser quirks that could change in future)
Minimal cross browser issues (ideally, should work on IE8+ with minimal IE-specific markup)
Here's the simplest I can come up with. Code snippet below. It's basically an existing method for vertically centring floats, putting the background on the middle wrapper, and setting fixed pixel gaps using padding on the outer wrapper rather than margins with box-sizing: border-box;.
JSBIN demo
Three HTML elements per block - which seems to be the minimum for any floated vertically centred content where the inner content doesn't have a known height.
No JS
Only the % width needs to change to change the number of blocks per line
If the text content is too big for the div, the div expands slightly without breaking the layout - overflow: hidden; can be applied if this is undesirable
Works on IE8 with no issues (fails on IE7 if any poor souls still need to support IE7)
.box-outer {
box-sizing: border-box;
float: left;
/* editable */
width: 50%;
height: 110px;
padding: 1px 1px 0px 0px; /* sets gap */
/* Padding does't collapse like margins - 1px all round gives 2px gaps */
}
.box {
width: 100%;
height: 100%;
box-sizing: border-box;
display: table; /* height doesn't fill without display: table */
/* editable: */
background: #99ffff;
padding: 8px;
}
.box-inner {
vertical-align: middle;
display: table-cell;
}
.boxes-container {
padding: 0px 0px 1px 1px; /* opposite of each box's padding */
/* editable: */
background: #ffffff url('http://freedesignfile.com/upload/2012/10/sky_clouds_03.jpg');
}
<div class="boxes-container clearfix">
<h2> Title </h2>
<div class="box-outer">
<div class="box">
<div class="box-inner">
Box content
</div>
</div>
</div>
<div class="box-outer">
<div class="box">
<div class="box-inner">
Box with longer content
</div>
</div>
</div>
<div class="box-outer">
<div class="box">
<div class="box-inner">
Box
</div>
</div>
</div>
<div class="box-outer">
<div class="box">
<div class="box-inner">
Box with significantly longer textual content
</div>
</div>
</div>
<br/>
<p style="text-align: center;"> <--- responsive width ---> </p>
</div>

HTML div height greater than intended

I'm trying to brush up on my HTML and CSS again and I was trying to make a simple layout. Here is the HTML/CSS for my simple site.
<!DOCTYPE html>
<HTML>
<HEAD>
<TITLE>My website</TITLE>
<META CHARSET="UTF-8">
<style type="text/css">
* {
padding: 0px;
margin: 0px
}
html, body {
margin:0;
padding:0;
height:100%;
border: 0px;
}
#TopBar {
width:100%;
height:15%;
border-bottom:5px solid;
border-color:#B30000;
}
#MidBar {
background-color:black;
height:70%;
width:70%;
margin-left:auto;
margin-right:auto;
}
#BottomBar {
position:absolute;
bottom:0;
width:100%;
height:15%;
border-top:5px solid;
border-color:#B30000;
}
h1 {
font-family: sans-serif;
font-size: 24pt;
}
#HEADER {
text-align:center;
}
li {
display:inline;
}
#copyright {
text-align: center;
}
</style>
</HEAD>
<BODY>
<DIV ID="TopBar">
<DIV ID="HEADER">
<HEADER>
<H1>My website</H1>
<NAV>
<UL>
<LI>About me
<LI>Contact me
<LI>My blog
<LI>My portfolio
</UL>
</NAV>
</HEADER>
</DIV>
</DIV>
<DIV ID="MidBar">
<DIV ID="PhotoSlideshow">
test
</DIV>
</DIV>
<DIV ID="BottomBar">
<FOOTER>
<P ID="copyright">Name here ©
<?PHP DATE("Y") ECHO ?> </P>
</FOOTER>
</DIV>
</BODY>
</HTML>
Given the heights I've applied to my div elements I expected everything to line up nicely however it appears that the bottom div is higher than the intended 15% and overlaps onto the middle div, see here demonstrated by the red border at the bottom...
Where am I going wrong? I'm sure it's something simple.
You should understand how the box model works... You are using borders which are counted outside the element, so for example if your element is 200px in height, and has a 5px border, the total element size will be 210px;
So considering this as the concept, what you are having elements which sums up to 100%, and you are using borders too, so that is exceeding the viewport which will result in vertical scroll...
Also you don't have to use position: absolute;, you are making it absolute, just to avoid scrolls but that's a wrong approach. Absolute element is out of the document flow, and will give weird results if you didn't wrapped inside a position: relative; element.
Demo
Few Tips :
Use lowercase tags
Avoid Uppercase ID's unless required
Using 100% vertically is very rare, designers generally use width: 100%; for making the layouts responsive. So if you don't have any specific reason to go for 100% vertical elements, don't go for it..
Solution:
Still if you want to stick with the vertical layout spanning to 100% in height, you should use box-sizing: border-box; property...
What box-sizing will do here?
Well, using the above property, it will change the default behavior of the box-model, so instead of counting the borders, paddings etc outside the element, it will count inside it, thus it will prevent the viewport to be scrolled.
I will provide you an example, which I had made for another answer.
Demo 2 (Updated, had forgot to normalize the CSS)
Explanation for the above demo, if you look at the CSS, I am using
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
which will make every element paddings, borders etc to be counted inside the element and not outside, if you mark, am using a border of 5px; and still, the window won't get a scroll bar as the border is counted inside the element and not outside.
There are many things a bit off with your code, however the straight forward answer is that borders are part of the box model, therefore part of the height calculation. So the height of your div is 15% of the height + the width of your borders, thus it is oversized.
Please see this explanation of the box model:
http://css-tricks.com/the-css-box-model/
I think it has to do with your borders (each of which is 5px). Since you have your TopBar, MidBar, and BottomBar have percentage heights that add up to %100, WITH additional borders, you have a problem of having an effective height of greater than %100, and then, because you have BottomBar with an absolute position at the bottom, it doesn't force the page to scroll, but simple induces some overlap between the MidBar and BotomBar divs.
Remove "Position: absolute" from: #BottomBar. That should do the trick.

CSS content overflow out of box IE <6

I have a div that holds some text, it has a background with a border, but for some reason the box is not expanding to the text, even with overflow: auto; here is my script for the box as well as a picture:
.box { background: #ffdcba; border: 1px solid #f78d25; display: block; clear: both; margin: 4px 0px; padding-left: 15px; overflow: auto; }
the divs inside are just floating, left and right, and have display: inline on them. heres a picture:
http://i45.tinypic.com/2woj1br.gif
A floated box will not expand to fit its contents. You need to add a clearing element after your content. <br> is usually good.
YOu don't specify the exact construction of the HTML, but I"m asssuming you've got something like this:
<div class="box">
<div style="float: left">test subject></div>
<div style="float: right">
<div>ASD</div>
etc...
</div>
</div>
Floating elements removes them from the regular flow and will cause the "overflow" you are seeing. You need to add a non-floated element below the floated parts to force the containing div.box to "expand" to contain the floats:
<div class="box">
<div style="blah blah" ....
etc....
<br style="clear: both" />
</div>
As well, the overflow: auto will not have any effect on your .box style, because it does not specify any height or width - it will naturally just expand to contain whatever content you put in there. To force a scrollbar to appear, you need to put in either height or width styling, and enough content to exceed either of the limits.

2 column CSS div with stretchable height

Related (possibly duplicate) questions:
How do I achieve equal height divs with HTML / CSS ?
Make Two Floated CSS Elements the Same Height
Hello, every one,
I tried for hours to create a stretchable 2 columns div but without any luck. here is my html code and my css code below it
<div class="two_cols_container">
<div class="two_cols">
<div class="left-col">
test
</div>
<div class="right-col">
test
</div>
</div>
</div>
my css code is
.two_cols_container {
width: 100%;
height: 100%;
}
.two_cols {
position: relative;
margin: 0 auto;
border: 1px solid black;
height: 100%;
height: auto !important;
min-height: 100%;
}
.two_cols .left-col {
/*position: absolute;
left: 0;*/
float: left;
}
.two_cols .right-col {
/*position: absolute;
right: 0;*/
float: right;
}
any idea?
A: either use float OR absolute positioning to make your columns. not both. You can just float both the columns to the left and it should be ok with no absolute positioning.
B: you're big problem is the columns can't be next to each other if both of their' widths are 100%. There's no way they can sit side by side in their containing element when they both take up the whole width. Set the width to at most 50%, but I'd go with a little lower to account for some browser bugs.
EDIT: I agree with Sneakiness, wet the width to something lower than 50%, because the margins and padding have to fit too.
There's
Tables ( you probably wouldn't want to rely on this )
Faux Columns ( the most practical way, faking columns going down using images - see http://www.alistapart.com/articles/fauxcolumns/ )
Border Trick ( a little complex but this only works for solid colors )
Padding / Margin / Clipping ( another complex one I wouldn't recommend )
I'd go with #2. If you need colors that are backgrounds of those columns to go all the way down, set a background on the container of those columns and make sure it repeats vertically, e.g,
div#wrapper { background:url(/images/faux.gif) repeat-y; }
If the columns are floated make sure to have overflow:hidden and a hasLayout trigger for IE like a width.
By the way since you have floats, apply overflow:hidden to .two_cols selector and add this rule:
html, body { height:100%; }
I found this method to be the simplest and most effective of all equal-height two-column layouts. You don't have to fake anything, and it Just Works.
If you mean that you want a fluid two-column layout, you need to set margins for both columns separately to position them both on the page.
You can use div style property to create as many columns you need, with what ever CSS effect you need :
<div style=”width: 100%;”>
<div id=”left” style=”float: left;">
<--! your text here -->
</div>
<div id=”right” style=”float: right;">
<--! your text here -->
</div>
</div>
Source and example : WordPress Tutorial Series - Basics about HTML and CSS

Resources