This question already has answers here:
How can I reorder my divs using only CSS?
(27 answers)
Closed 6 years ago.
Given that the HTML
<div>
<div id="content1"> content 1</div>
<div id="content2"> content 2</div>
<div id="content3"> content 3</div>
</div>
render as
content 1
content 2
content 3
My question:
Is there a way to render it as below by using CSS only without changing the HTML part.
content 1
content 3
content 2
This can be done in browsers that support the CSS3 flexbox concept, particularly the property flexbox-order.
See here
However, support for this is only in current versions of most browsers still.
Edit Time moves on and the flexbox support improves..
This works for me:
http://tanalin.com/en/articles/css-block-order/
Example from this page:
HTML
<div id="example">
<div id="block-1">First</div>
<div id="block-2">Second</div>
<div id="block-3">Third</div>
</div>
CSS
#example {display: table; width: 100%; }
#block-1 {display: table-footer-group; } /* Will be displayed at the bottom of the pseudo-table */
#block-2 {display: table-row-group; } /* Will be displayed in the middle */
#block-3 {display: table-header-group; } /* Will be displayed at the top */
As stated there, this should work in most browsers. Check link for more info.
It might not exactly match what you're after, but take a look at this question:
CSS positioning div above another div when not in that order in the HTML
Basically, you'd have to use Javascript for it to be reliable in any way.
This is one of the classic use-cases for absolute positioning--to change rendering from source order. You need to know the dimensions of the divs to be able to do this reliably however, and if you don't javascript is your only recourse.
I was messing around in Firefox 3 with Firebug, and came up with the following:
<div>
<div id="content_1" style="height: 40px; width: 40px; background-color: rgb(255, 0, 0); margin-bottom: 40px;">1</div>
<div id="content_2" style="width: 40px; height: 40px; background-color: rgb(0, 255, 0); float: left;">2</div>
<div id="content_3" style="width: 40px; height: 40px; background-color: rgb(0, 0, 255); margin-top: -40px;">3</div>
</div>
It's not perfect, since you need to know the heights of each container, and apply that height value to the negative top margin of the last element, and the bottom margin of the first element.
Hope it helps, nd
I got it to work by doing this:
#content2 { position:relative;top:15px; }
#content3 { position:relative; top:-17px; }
but keep in mind that this will not work for you as soon as you have dynamic content. The reason I posted this example is that without knowing more specific things about your content I cannot give a better answer. However this approach ought to point you in the right direction as to using relative positioning.
One word answer: nope. Look into XSLT (XML Stylesheet Language Transforms), which is a language specifically geared towards manipulating XML.
If you know the height of each element then it is a simple case of vertical relative positioning to swap around the orders. If you don't know the heights then you either have to give them heights and allow the divs to get scroll bars if there is any overflow or calculate it all with JavaScript and add the relative positioning on-the-fly.
with jquery you can simply do:
$('#content2').insertAfter($('#content3'));
I don't think there's a way to do it with CSS, except to force fixed positioning of each of the divs and stack them that way.
Related
For a webpage grid-layout I decided to use Flexbox. Now I wanted to implement some "auto-functionality", so that grid-boxes can later be inserted without the need to add classes or styles in the HTML. One of this features is to make a box allways be 75% as tall as it is wide - even if the box is resized by, for example, browserwindow resize. Off course, if the boxes content extends the 75%-height, it should (and only then should) increase its height to fit the content. I searched for hours to find a suitable solution, but I finally got it working. So I thought at least, until I added content to the box.
The auto aspect-ratio works fine, as long as the box is empty. If I add content, the 75% of the width is allways added to the height it has through extension by its content. I made a jsfiddle to clearly visualize the problem:
JSFiddle wd5s9vq0, visualizing the following Code:
HTML-Code:
<div class="container">
<div class="content-cell"></div>
<div class="content-cell"></div>
</div>
<div class="container">
<div class="content-cell">
This cell has an inreased height because of
it's content. The empty space below the
content is the 75% of the cells width.
</div>
<div class="content-cell"></div>
</div>
CSS:
.container {
display: flex;
width: 400px;
}
.content-cell {
flex: 1 1 0;
margin: 10px;
background-color: #ccc;
}
.content-cell::after {
content: "";
display: block;
padding-top: 75%;
}
If I didn't knew it better, it looks like a floating-problem - but I think the ::before / ::after selector should add the block-element before the element it is used on and not inside it.
Does anyone has an idea on how to fix this problem?
This seems to be a very widespread problem on the internet, and most solutions you find are either about wrapping the content, absolute-positioning the content or a mixture of both. This has numerous and case-dependent downsides. After hours of playing around with the code, I finally found a combination of CSS proporties that work without the need to add any DOM or make the content absolute-positioned. This looks quit basic, and I am wondering why it took me so long and why you can't find it out there on the web.
The HTML:
<div class="mybox aspect-full">
This is text, that would normally extend the box downwards.
It is long, but not so long that it extends the intended aspect-ratio.
</div>
The CSS:
.mybox {
width: 200px;
}
.aspect-full::before {
content: '';
display: block;
padding-top: 100%;
float: left;
}
The only downside I could find is that the content of your cell must float. If you use clear on one of your child objects, it is positioned below the expander-block and you are back to the original problem. If you need to clear the floating of divs inside of these aspect-ratio-cells, you might consider to wrap them and keep the wrapper floatable.
Roughly speaking, attempting to build a four-column layout, I've got this HTML:
<div>
<div>A column</div>
<div>A column</div>
<div>A column</div>
<div>A column</div>
</div>
And I've got this CSS:
div {
background: #ccc;
}
div div {
background: #eee;
display: inline-block;
width: 25%;
}
-> Fiddle me this <-
When rendered in the browser (Currently, I have been testing with Chrome only) the whitespace between the nested div elements (in this example the whitespace is caused by line breaks) is rendered, thus throwing my layout out.
Clearly, I can float my nested divs...
div {
background: #ccc;
}
div div {
background: #eee;
width: 25%;
float: left;
}
-> Fiddle me that <-
But then my container div collapses and I don't want to have to have to use CSS clearfix hacks or extra HTML to open it back up.
Alternatively I can modify my HTML such that the whitespace is removed...
<div><div>A column</div><div>A column</div><div>A column</div><div>A column</div></div>
but that makes it hard to work with. The alternative of breaking the tags so that it becomes more readable somehow leaves me feeling dirty...
<div>
<div>A column</
div><div>A column</
div><div>A column</
div><div>A column</div>
</div>
I've found a resource or two (I failed to find anything on SO) but I don't really like any of the solutions - they are all workarounds, which I will entertain if I must but surely there's an alternative?
So my question(s)... is there a cross-browser, w3c-compliant, non-javascript, hack-free, tidy HTML, bombproof way of preventing HTML whitespace from being rendered in the browser whilst using display:inline-block? Or is there an alternative to inline-block that can be used that has no unpleasant side effects?
EDIT
Assuming that this is genuinely impossible, the best solution would be something that required no addition HTML markup and 'flexible' CSS. In other words, a webmaster could edit the HTML as normal without consideration of breaking the layout, and the CSS (hacked or otherwise) will accommodate the webmaster's amends without having to be amended itself.
MY "WORKAROUND"
Well, it looks like something's got to give. In my situation it is more important to have HTML that doesn't require extra markup so the best solution is to work in a CSS hack that "just works" invisibly. The solution is to float the nested divs and add a hack...
div div {
float: left;
}
div::before,
div::after {
content: "";
display: table;
}
div::after {
clear: both;
}
div {
*zoom: 1;
}
...which is a derivation of a fix I've been using for some time and was hoping to avoid. This succint version of the fix was found on this site.
So now every single div in the markup has got the clearfix hack applied to it whether it needs it or not. I'm yet to learn if this has any bad side-effects by being applied to all divs - I look forward to debugging and fixing when any problems surface ;-)
You provided nearly all possible solutions to this big layout question. I just want to point out my preferred solution.
Set font-size to the parent to 0 and resetting it again with REM's.
You'll have no trouble with your code and layout if there is no additional text inside the parent div (not the child divs).
REM's (Relative EM's) are not relative to the font-size of the parent elements (like normal EM's are), but relative to the root element of your document – the html element.
HTML:
<div class="parent">
<div class="child">column 1</div>
<div class="child">column 2</div>
<div class="child">column 3</div>
<div class="child">column 4</div>
</div>
CSS:
html {
font-size: 1em;
}
.parent {
font-size: 0;
}
.child {
display: inline-block;
font-size: 16px; /* Add pixel-based font-size to support IE8 and below */
font-size: 1rem; /* Don't use rem along with the font-shorthand to avoid problems in IE9/10 - see note below */
width: 25%;
}
No Browser support:
IE8 and below: Add pixel-based font-size to make it work.
IE9/10: not working with font-shorthand; use font-size instead!
(Opera Mini & iOS 3.2)
is there a ... way of preventing HTML whitespace from being rendered in the browser whilst using display:inline-block?
Yes, there are several ways. None of them really meet your criteria of 'hack-free' and 'tidy', but they do work.
Reformat ('minify') your code so that it doesn't have any white space between the elements.
This is probably the most hack-free and cross-browser solution. It isn't necessarily tidy though, and it means you're fixing your layout by adjusting the HTML rather than the CSS, which isn't ideal. But it does work well. If you want to keep your code readable, you could use HTML comments so you can keep the gaps but without them being in the DOM:
<div>block 1</div><!--
--><div>block 2</div><!--
--><div>block 3</div>
Still not ideal, but more readable than a massive single line of code.
Set the font-size to zero for the container, and back to full size again for the blocks.
This works really well. It's a pure CSS solution and easy to do. The down side is that it can be difficult to work with if you've got relative font sizes (ie setting back to 14px is fine, but setting to 1em won't work because 1em of the previous font size of zero is still zero).
Set a 1em negative margin to close the gap.
This also works pretty well, but can be imprecise.
Or is there an alternative to inline-block that can be used that has no unpleasant side effects?
There's always float:left. But that's got a whole range of different issues of its own. If you're using inline-block, the odds are good it's because you don't want to use floats.
Use position:absolute and do the layout manually.
You can use the float method you described in your question, but you didn't clear your floats, which is why the container collapses.
A good method is to use an ::after pseudo element attache to the container element to "auto-clear" itself:
div:after {
content: "";
display: table;
clear: both;
}
http://jsfiddle.net/s2rJW/3/
When i saw your "workaround" i was thinking: Why don't you use a <table>?
And then i figured this out:
div {
background: #ccc;
display: table;
width: 100%;
}
div div {
background: #eee;
display: table-cell;
width: 25%
}
<div>
<div>A column</div>
<div>A column</div>
<div>A column</div>
<div>A column</div>
</div>
I recently start to learn CSS and table less design.
After reviewing some tutorials now I am involved with converting PSD Mockup to XHTML and CSS.
Most often my problem is to positioning elements and containers.
for example this below design:
I am converting this to CSS and HTML.
I have no problem with styling Input elements.
about main layout it seems two columns layout , right ?
How do I style containers ?
I wrote this code It displays better here.
I divided my page to two containers and valued (float:left) to left container.
As specified in jsFiddle link elements on the left side container had come out of the box (I think its because of float).
I can't set containers position to absolute.
Now please help me to refactor and change my code. And please explain to me how to position elements right ?
i think a
<div style="clear:both;"></div>
before the </div> of the container will work.
edit:
http://jsfiddle.net/xNwAc/5/
Try and have a wrapping element to contain your two columns. with W3C code, you'll want to use floated elements. The elements don't have any padding, you can work on them yourself, but it's a very basic structure to follow:
The CSS:
#wrapper { width: 960px; margin: 0 auto; background: blue; } /* positions it center of page */
#left { float: left; width: 50%; background: red;}
#right { float: right; width: 50%; background: green;}
The HTML:
<div id="wrapper">
<div id="left"> Left content </div>
<div id="right"> Right content </div>
</div>
You have to set a new formating context on the container, with overflow:auto; eg.
I sugger you to read the specification which is very clear and useful.
As the exclamation point is not a part of the content you can place it as a background image.
OK so what would happen if I have 2 divs (one containing text, the other an image). The image always has a static width but the text varies. hence making its containing div variable.
I can make it work for all other browsers (except IE6 and IE7) by using CSS display:table. IE6 and 7 don't have that so I can't find a workable solution to center them all.
... so you know what I'm talking about...
.container{text-align:center; width:100%}
.container .centered{display:table; margin:0 auto}
<div class="container">
<div class="centered">
<div id="text">varying length text</div>
<div id="image">IMAGE</div>
</div>
</div>
Quite apart from the lack of IE support, setting display: table as you have without its children using display: table-row/table-cell results in undefined behaviour. It doesn't make sense to put block elements directly inside a table element and the browser might do anything at all.
What you are trying to do is get shrink-to-fit width behaviour without using float, which is a normal way of getting shrink-width but requires that the block in question goes to the left or right not centre. Probably a better way of saying that would be to use an inline-block:
.centered { text-align: center; }
.centered span { display: inline-block; border: dotted red 1px; }
<div class="centered">
<span id="text">varying length text</span>
</div>
<div class="centered">
<span id="image">IMAGE</span>
</div>
(You have to use a naturally-inline element like span to make it work under IE<8; div would fail. There is also -moz-inline-box if you need to target Firefox 2.)
Are you using quirksmode or standards compliant mode? In other words have you included a DOCTYPE declaration at the top of your html page?
You shouldn't need to use display:table just margin:auto should do the trick provided you are using a standards mode.
Sorry for the slightly rubbish title. I could not think how to describe this one better.
I am trying to implement the Google Friend Connect members gadget on my site, (just got into the scheme and want to put it in without a major redesign, at least for testing sake).
My problem is as follows:
I have a container div that has a width of 90% of the main page (body). Inside this I am floating a div to the right and setting its width to 300px and putting the google gadget inside it. What I would like is to be able to have a div fill 95% of the space remaining to the left of the google gadget div.
I don't know if it is possible to be able to mix px and % with divs and widths.
I hope this makes sense.
Thanks
It is. You're looking for a semi-fluid layout. The quest was was originally the holy grail of CSS implementation... But as you can see from that link (they're doing 3 columns, 2 fixed but it's easy to alter), it's a problem long solved =)
If you prefer to avoid floats and clearfixes, use flex layout.
.main {
display: flex;
width: 90%;
}
.col1 {
flex-grow: 1;
}
.col2 {
width: 300px;
margin-left: 5%;
}
<div class="main">
<div class="col1" style="background: #518cf3;">Left column</div>
<div class="col2" style="background: #94d0bb;">Right column</div>
</div>
Note: Add flex vendor prefixes if required by your supported browsers.
I did a quick experiment as well after looking at a number of potential solutions all over the place. What I was trying to do was to have a mix of fluid and fixed rows and columns.
This is what I ended up with:
http://jsbin.com/hapelawake