I'm testing something where I show 4 over-sized images centered in quadrants that fill a screen. So 2 rows and 2 columns.
□□
□□
The images are in the backgrounds of 4 divs which should stack. All divs have small borders.
My issue is that the height works but for the width I need to deduct 9px from the width of each box to make them stack and they no longer fill the screen. Without 9px they look like:
□
□
□
□
What is this 9px gap?
Best to see it in a jsfiddle
#wrapper {
background: pink;
border: 5px red solid;
}
#container {
background: fuchsia;
border: 5px purple solid;
}
#content {
background: aqua;
border: 5px blue solid;
}
#parent {
background: lime;
border: 5px green solid;
}
#image1,
#image2,
#image3,
#image4 {
background: yellow;
border: 5px orange solid;
/* Each div fill 1/4 screen so get 50% user screen viewport height/width and deduct the height/width of everything outside of the image divs content area (box model).
So here we must deduct the 1 x 5px border on one side (image border) and 4 x 5px borders on the other side (image, parent, content & wrapper borders)*/
height: calc(50vh - (5*5px));
/* The line below should be the same as above ie:
width: calc(50vw - (5*5px)) but I need to deduct a further unexplained 9px and now
the 4 image divs wont fill the screen? */
width: calc(50vw - (5*5px + 9px));
float: left;
/* set and center a background image to the div */
background-image: url("http://dev.bowdenweb.com/tools/i/pixelgrid.png");
background-position: center;
}
.clearfix:after {
content: "";
display: table;
clear: both;
}
<div id="wrapper">
<div id="content">
<div id="parent" class="clearfix">
<div id="image1">
</div>
<div id="image2">
</div>
<div id="image3">
</div>
<div id="image4">
</div>
</div>
</div>
</div>
Floats aren't designed for layouts. Yes, they've been used this way for decades... as a hack (CSS offered no better alternative). Floats were designed to wrap text around images, not build grids.
Viewport percentage lengths are relative to the initial containing block, not the parent element, like percentage lengths.
You combine floats, borders, viewport percentage widths and box-sizing:content-box, and you get your 9px mystery gap. (I didn't delve any further as my focus was a modern solution to your problem.)
Today there is CSS3, which offers two methods for building layouts: Flex Layout and Grid Layout
Browser support for grid layout is still weak.
Browser support for flex layout is almost complete.
Here's your layout using flex, box-sizing:border-box, and percentage heights:
html {
height: 100%;
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit; /* https://css-tricks.com/box-sizing/ */
}
body {
height: 100%;
margin: 0; /* remove default margin */
}
#wrapper {
background: pink;
border: 5px red solid;
height: 100%;
}
#container {
background: fuchsia;
border: 5px purple solid;
height: 100%;
}
#content {
background: aqua;
border: 5px blue solid;
height: 100%;
}
#parent {
background: lime;
border: 5px green solid;
display: flex; /* establish flex container */
flex-wrap: wrap; /* allow children to wrap */
height: 100%;
}
#image1, #image2, #image3, #image4 {
background: yellow;
border: 5px orange solid;
height: 50%;
flex-basis: 50%; /* each item 50% wide */
background-image: url("http://dev.bowdenweb.com/tools/i/pixelgrid.png");
background-position: center;
}
<div id="wrapper">
<div id="content">
<div id="parent" class="clearfix">
<div id="image1"></div>
<div id="image2"></div>
<div id="image3"></div>
<div id="image4"></div>
</div>
</div>
</div>
jsFiddle
Benefits:
No more mystery gap.
No more floats.
No more clearfix.
No need to add up borders and use calc.
Cleaner, more efficient code
Layout is responsive
Unlike floats and tables, which offer limited layout capacity because they were never intended for building layouts, flexbox is a modern technique with a broad range of options.
To learn more about flexbox visit:
Methods for Aligning Flex Items
Using CSS flexible boxes ~ MDN
A Complete Guide to Flexbox ~ CSS-Tricks
What the Flexbox?! ~ YouTube video tutorial
Browser support:
Flexbox is supported by all major browsers, except IE 8 & 9. Some recent browser versions, such as Safari 8 and IE10, require vendor prefixes. For a quick way to add all the prefixes you need, use Autoprefixer. More details in this answer.
The problem is that you are calculating the images sizes (child divs) in base to an absolute width view port (vw), and you are including borders. The sections fit well when the web browser have a size that match exactly with the calculation of the border.
My recomendation is to use to calculate the size using the old % method,
Try to replace:
width: calc(50vw - (5*5px + 9px));
by:
width: calc(50% - 10px);
See the example in jsFiddle
The problem is with the scrollbars (which are included in the vw/vw).
If you make the body hide its overflow it will work with your initial calculations (see https://jsfiddle.net/yLgcLd7j/6/).
But to make life simpler you can avoid these by setting box-sizing:border-box and using the vh/vw units on the containers and the rest make them percentage based.
#wrapper, #wrapper *{box-sizing:border-box;}
#wrapper {
background:pink;
border:5px red solid;
width:100vw;
height:100vh;
}
#container, #content, #parent{width:100%;height:100%;}
#image1, #image2, #image3, #image4 {
border:5px orange solid;
float:left;
width:50%;
height:50%;
/* set and center a background image to the div */
background-image: url("http://dev.bowdenweb.com/tools/i/pixelgrid.png");
background-position: center;
}
Demo at https://jsfiddle.net/yLgcLd7j/8/
Related
here's a simple problem for you to solve.
The image should be 90vw and the container should add a border to the image.
The border can't be applied directly to the image, since the image in further steps of coding will have some style directly applied to the html.
The current implementation causes the border to be smaller than the image. How can it wraps nicely around the image?
I really want something simple to keep it light and easy to understand for a newbie like me, so please no codes that do triple flips and pike jumps with gentle, graceful landings like I usually see on Stack Overflow.
HTML:
<div id="main-image-container-slideshow">
<img id="main-image-slideshow" src="http://localhost:8888/image/jpeg/campus1.jpg">
</div>
CSS:
#main-image-container-slideshow {
border: 5px solid black;
}
#main-image-slideshow {
width: 90vw;
}
I would make the container be 90vw AND have the container have the border. The image would then be the full width of the 90vw container. I made the image a block to remove any potential unwanted space underneath.
#main-image-container-slideshow
{ border: 5px solid black;
box-sizing: border-box;
width: 90vw;
/* If you want the container to be centered, add this, otherwise skip */
margin: 0 auto;
}
#main-image-slideshow
{
width: 100%;
display: block;
}
You can set the display property of the wrapper to flex and set the flex-direction property to column. And, if you decide to change the width of the image, then you won't have to change the display property in CSS.
#main-image-container-slideshow {
display: flex;
flex-direction: column;
border: 2px solid white;
}
#img {
width: 90vw;
}
html {
background-color: black; /* sets the background color to black to make it easier to see the border */
}
<div id="main-image-container-slideshow">
<img id="main-image-slideshow" src="https://img.freepik.com/free-photo/wall-wallpaper-concrete-colored- painted-textured-concept_53876-31799.jpg?size=626&ext=jpg">
</div>
The image used in the code snippet was found at freepik.
You can set the container width to 100vw and image width to 90% of the container's width which is equivalent to 90vw.
.image-container {
width: 100vw;
border: 5px solid #000000;
}
.image {
width: 90%;
}
<div class="image-container">
<img src="https://stackoverflow.design/assets/img/logos/so/logo-stackoverflow.png" class="image"/>
</div>
Actually it has to be a little less that 100% because 100% sets it a little off screen to the right. When I load my page on a tablet or laptop screen it zooms into the top left of the screen, if I zoom out I see that the divs only take up about half the page left to right. I've tried playing around with min-width with no luck.
.first {
height: 75px;
width: 99.55%;
background-color: red;
margin-top: 19px;
border: 3px yellow solid;
min-width: 1000px;
margin: 0 auto;
}
h2 {
text-align: center;
width: 100%;
}
<div class="animated fadeInUpBig first o">
<h2>Need to fix positioning on mobile</h2>
</div>
<div class="animated fadeInUpBig first t">
<h2>More work will be done tomorrow evening</h2>
</div>
<div class="animated fadeInUpBig first tr">
<h2>Make it look half good by weekend</h2>
</div>
If you are wanting each red block with yellow border to span a specific width (to be 90%, 300px, etc.), you can add box-sizing: border-box to the element which allows for the width to include both padding and border. However since both the .first (a div) and the h2 are both block levels elements, by default they will take up 100% width of their parent.
I consolidated the margin-top with the margin: 0 auto; which keeps the margin: from overriding the margin-top.
Also the shorthand for border should be width, style, and color, so I have altered it slightly.
Lastly, the body element has a default margin of 8px in most browsers, so in order to get your boxes to touch the outside of the browser window, you'll want to add that last body property or use a common CSS reset (such as http://meyerweb.com/eric/tools/css/reset/)
.first {
height: 75px;
background-color: red;
border: 3px solid yellow;
min-width: 1000px;
margin: 19px auto 0;
}
h2 {
text-align: center;
}
body {
margin: 0;
}
http://codepen.io/phawley/pen/amLRYK
Here is my css:
.contain
{
min-width: 300px;
background: black;
height: 200px;
display: inline-block;
overflow: auto;
}
.inl1{
/* margin: 5px 5px 5px 5px; */
min-width: 300px;
background: blue;
width: 400px;
height: 200px;
}
<div class=contain>
<div class=inl1></div>
</div>
<div class=contain>
<div class=inl1></div>
</div>
Clearly the two divs display inline, which is what I want.
However, when the browser is resized smaller the divs are displayed one above the other (desired behaviour), but once I make the browser window smaller than min-width, I need to have horizontal scrollbars displayed. This is not happening.
Any help as to why?
Edited: I tried the suggestions here, but they all seem to break the desired behaviour of the divs stacking on top of each other when the browser is sized smaller.
The effect I am after:
display the divs inline (with no scrollbars) in a browser that is wide enough; but in a "narrow" browser (ie mobile) display the divs one on top of another and THEN add horizontal scrolling ONCE the min-width can no longer be displayed for each div.
I think that's a little clearer...
You just need to have a wrapper for the divs and set it with
.wrapper{
min-width: 100%;
white-space: nowrap;
}
Here is the Fiddle: https://jsfiddle.net/1hshzxah/3/
Your outside boxes have the same minimum width as your inside ones, so both will be at least 300px wide, so no scrollbars appear. Because of the defined pixelwidth of your outer elements, your they will not stack next to each other if you do not have 600 pixels to play with or more. If you give your outer boxes a width that can scale (by using % or vw) with the page width, your result magically appears:
.contain {
width: 45%;
background: black;
height: 200px;
display: inline-block;
overflow: auto;
}
.inl1{
/* margin: 5px 5px 5px 5px; */
min-width: 300px;
background: blue;
width: 400px;
height: 200px;
}
#media all and (max-width:600px){
.contain {
width: 100%;
}
}
<div class=contain>
<div class=inl1></div>
</div>
<div class=contain>
<div class=inl1></div>
</div>
(I use 45% because I did not want to bother with floating these nicely next to each other, but you could with some more CSS). You can still add a max-width of 300 pixels to your containers to make sure they don't grow beyond 300px, but still shrink otherwise.
I wanted the behaviour of inline-block and float together of several divs in a responsive container (% width), where:
float effect:
1a. it would have divs left and right aligned
1b. when the window width shrinks - the space between the left and right divs would also shrink
inline-block effect:
2a. all the divs would be in the same line
2b. when the window width shrinks - it will hide the divs (usually starting on the right)
Examples:
when the window is larger that the divs:
when the window is smaller that the divs:
2a. the wanted effect
2b. the wrong effect
Here is a code example of what I got so far (which only simulates the float effect (1) and effect in same line (2b) but missing effect when shrinking the window width (3b) ), with a demo:
.item1 {background-color: red;}
.item2 {background-color: yellow;}
.item3 {background-color: blue;}
#container {
width: 95%;
height: 50px; /* not sure if is needed */
}
#container div {
display: inline-block; /* does nothing with floats */
width:100px;
height: 50px;
}
.left {float: left;}
.right {float: right;}
<div id="container">
<div class="item1 left">item1</div>
<div class="item2 right">item2</div>
<div class="item3 right">item3</div>
</div>
Notes:
The container has a % value (to be a bit responsive).
the width of the divs (items) is supposed to have a fixed width (to have a logo image, a menu, and some icons (more images), ...)
in the example, I've also added the inline-block just to show that it does not works with it
the example only uses 3 divs (1 left and 2 right), but if possible I preferred a solution where I could have more without changing too much of code.
(I want to avoid fixed position (like right:20px or 20%) to be easier to add new items.)
was supposed to find a solution using only html and css (or html5 and css3) (avoiding JavaScript).
You should take a look at bootstraps grid system. It would save you a lot of time. http://getbootstrap.com/2.3.2/scaffolding.html#gridSystem
May be it is not fully what you want, but it gets close:
use flex for the container, and hide the second row.
and play with flex-shrink, flex-basis, max-width and margin
.container {
width: 80%;
display: flex;
flex-wrap: wrap;
height: 100px;
margin-bottom: -100px;
border: solid 1px red;
overflow: hidden;
}
.container div {
height: 100px;
border: solid 1px;
}
.left {
flex: 200px 0 0;
background-color: lightgreen;
margin-right: auto;
}
.right {
flex: 100px 1 1;
background-color: yellow;
max-width: 200px;
}
.disappears {
flex: 200px 0 1;
background-color: papayawhip;
}
<div class="container">
<div class="left">left</div>
<div class="right">right</div>
<div class="disappears">dis</div>
<div class="disappears">dis</div>
</div>
You need to add overflow:hidden; to your #container
#container {
width: 95%;
height: 50px; /* not sure if is needed */
overflow: hidden;
}
After more research and tests, I finally come up with a solution, with a demo:
.item1 {background-color: red;}
.item2 {background-color: yellow;}
.item3 {background-color: blue;}
#container {
width: 95%;
display: flex;
justify-content: space-between;
}
/* affects container_left and container_right divs */
#container > div {
display: flex;
}
/* affects items */
#container > div > div {
width: 100px;
min-width: 100px; /* to avoid shrinking in IE 11*/
height: 50px;
}
#container, #container > div {
/* reading from right to left (RTL)*/
/* flex-direction: row-reverse; */
}
<div id="container">
<div class="container_left">
<div class="item1">item1</div>
</div>
<div class="container_right">
<div class="item2">item2</div>
<div class="item3">item3</div>
</div>
</div>
Notes:
It does the effects asked, at least in Firefox (v 37.0.2) and Internet Explorer (IE 11).
In chrome (v 42.0.2311.135 m) it doesn't respect the min-width. Maybe there's some way around it that I didn't realize.
Changed the html to put 2 containers for left and right items, (and if needed you could also add a middle container). And in css using the flex property with the "justify-content: space-between" to align the containers.
New items can be easily added to the right positions (just in html) without the need to use a grid system.
Also added some css code to uncomment if you want to reverse the item order (in right to left languages).
Here's what I'm working with:
<div id="parentDiv">
<div id="labelDiv"></div>
<div class="contentDiv"></div>
<div class="contentDiv"></div>
<div class="contentDiv"></div>
<!-- ... -->
</div>
labelDiv is always a fixed size. In this case, 30px. parentDiv is set to a width of 75%. There can be 1 to any number of contentDiv. What I want is to evenly space out the contentDiv objects. I'm trying to do this all in CSS (2.1, if possible). I was able to write a quick jQuery function to equally space out the divs, but I don't feel like its the best solution.
Any ideas?
display: table; table-layout: fixed can do this.
This is all CSS 2.1 as requested, but check the browser support - it works everywhere except IE6/7.
See: http://jsfiddle.net/thirtydot/Ec8Tw/
CSS:
#parentDiv {
display: table;
table-layout: fixed;
width: 75%;
height: 100px;
border: 1px solid #444
}
#parentDiv > div {
display: table-cell;
border: 1px dashed #f0f
}
#labelDiv {
width: 30px;
background: #ccc
}