Can I select CSS siblings out of order? - css

I'm trying to write css to style my columns automatically based on the elements on the page. There are several combinations of columns:
aside-article-aside
aside-article
article-aside
article
Each aside will have a class of either left or right, depending on which side of the screen it is on. The asides will always be a constant width no matter what the layout, but the article's width will change depending on the layout.
I want to use CSS (preferably without any javascript) to set the width of the article. I've been playing around with CSS siblings, but I can't quite get this to work. This is how I would theoretically like the code to work:
article{
/* just article */
width: some width;
}
.left~article{
/* aside-article */
width: some width;
}
.right~article{
/* article-aside */
width: some width; /* (this can be the same as the previous;
I don't know if it's easier to define
them together or separately) */
}
.left~.right~article{
/* aside-article-aside */
width: some-width;
}
The first two layouts work, bu the second two do not. The problem is that I always want to style the article, even if it is not the last in that section of the DOM. Using the selectors article~.right and .left~.article~.right for the last two layouts respectively finds the correct combination of layouts (i.e. either an article then an aside or an article between two asides) but then it targets the right-most aside and I can't change the style of the article.
Is there a way to take all siblings into account whether before the target element in the DOM using the sibling selectors in CSS? Or can anyone think of any "creative" ways I could get around this without having to use javascript?
Thanks!

CSS3 Solution
Assuming the containing element for these only has immediate children of either aside or article, then there is a CSS3 solution (so IE9+). For my example here, I am assuming an overall width of 400px and standard widths for aside elements (though that could be different).
aside {
width: 100px;
}
aside.left + article,
article:first-child {
width: 300px;
}
article:only-child {
width: 400px; /* overrides article:first-child if it is only-child */
}
aside.left:nth-last-of-type(2) + article {
width: 200px; /* only engages if there are two asides */
}

Related

CSS good practices for responsive Height. This is a quick fix/MacGyver or not?

I made this code that makes a responsive height, it adjusts according to the size of the viewport. (Run the snippet and resize the screen).
Whereas the html and body have a height: 100%, I set up a basic structure with 3 divs and I was handing this height: 100% between them (as you can see in the snippet). After that, I gave a position: absolute and top according to the size of each.
Well, as I assign attributes the top for each div in "hand", I got the feeling that this may be a quick fix/MacGyver on it, because as in the later, there are more divs, I have to do this calculation for top again. I think that have better ways to do this...
Thus, in what other ways I can do this? The code that I did can be considered a quick fix/MacGyver?
html, body{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.div1{
position: absolute;
width: 100%;
height: 10%;
background: red;
}
.div2{
position: absolute;
top: 10%;
width: 100%;
height: 75%;
background: green;
}
.div3{
position: absolute;
top: 85%;
width: 100%;
height: 15%;
background: yellow;
}
<div class="principal">
<div class="div1"></div>
<div class="div2"></div>
<div class="div3"></div>
</div>
The answer to whether what you're doing is a good solution (which I will interpret as concise, not overly complicated, and as compatible as possibe) depends on what exactly you're trying to do. Because you don't provide much detail on that end, let me give you the rundown.
The generally best approach (by the definition above)
In most cases, you won't need any special properties and can simply set the height or min-height of your three containers to the appropriate value, since their parent (body) already has a height of 100%. Because everything is underneath each other, there is no need to use the position property in any way.
Because of the way html works by default, these containers will retain their size until their content will require more space; then they will expand to accomodate the content. This is a feature, not a bug.
If you want to prevent this, set the overflow to hidden or scroll, which will help retaining the original container size (though in case of scrolling, scrollbars might mess with your plans).
Alternative solutions
Sometimes layouters get weird ideas of what you need to put on a webpage, and weird ideas might require weird solutions. Let me try to come up with a list of options to choose from:
The approach you took works if you need to split the viewport into exact shares of fix values, disregarding the container's contents entirely. It's compatible with any relevant browser by a long shot, but it will (assuming you handle the overflow so it doesn't stretch the container) likely result in cut-off content on extreme screen sizes (if you have primarily text content) or aspect ratios (if you have primarily image content); to be honest, probably both - but if you're working on a game, for example, maintaining a relative container size can easily be more important than their contents
Flexboxes will "only" give you a benefit of stretching the content over the whole screen if you're desperately trying to avoid setting a height, but it shouldn't result in any unforeseen errors, aside from the compatibility issues. As an additional bonus, you can rearrange the containers with the order property, which none of the other methods will accomplish.
Using absolute-positioned elements, you can entirely disregard height attributes and just set both top:0 and bottom:0 (while having a relative-positioned parent) to stretch a container over the entire height, then position containers inside on the top and bottom the same way. Not many cases in which this is more useful than the above two come to mind, and you won't like fixing any problems you encounter on the way, but if you're developing for browsers thathave issues with overflow properties, you could look into it.
The vh unit, apart from suffering from compatibility issues about the same, can be used, but don't pose any actual benefit over using percentage values. They are used to size elements relative to the viewport dimensions, which your percentage solution does just the same for this specific use case.
You could use a table, though that's commonly considered bad practice for various reasons and will on top of that be the most complicated solution of all of these, so I won't go into it.
So, all in all, there are many ways to accomplish what you want (and I possibly even missed some), and without providing info about the exact nature of what you're trying to do, there can be no exact recommendations other than a quick summary of what I wrote above: If you plan on putting content in the top and bottom container and you can't use the topmost solution, flexbox will work the best for you; if you need the containers to take up precisely a certain percentage, go with your original solution; and only if both aren't suitable, expand your search to the other options.
Today flex can make this really easy:
examples to run in full page:
html, body {
height:100%;
/*
}
next can be declared only for body but won't hurt if both html/body
body {
*/
display:flex;
flex-flow:column;
}
main {flex:1;
}
/* makeup */
header, footer {
background:tomato;
padding:1em;
}
main {
background:turquoise;
margin:1em;/* it can even stand away */
}
<header> header no need to set an height </header>
<main> let's fill remaining space</main>
<footer> footer no need to set an height </footer>
or use many div
html,
body {
height: 100%;
}
body {
display: flex;
flex-flow: column;
}
div {
flex: 1;
}
/* makeup */
header,
footer {
background: tomato;
padding: 1em;
}
div {
background: turquoise;
margin: 1em;/* it can even stand away */
}
div.autoH {
flex: none;
margin: 0.25em 0em;
background: brown
}
<header>header no need to set an height</header>
<div>let's fill remaining space</div>
<div class="autoH">let's fill only my needed space</div>
<header>or use header's / footer's properties</header>
<div>let's fill remaining space</div>
<footer>footer no need to set an height</footer>

Height of parent element containing only floats collapse to nothing. How to fix it?

One of the more bewildering things about working with floats is how they can affect the element that contains them (their "parent" element). If this parent element contained nothing but floated elements, the height of it would literally collapse to nothing. This isn't always obvious if the parent doesn't contain any visually noticeable background, but it is important to be aware of.
I have background-image in parent element and 2 sub float elements. As above description says, its (parent element)height collapses to zero whenever it has only float elements. How can I fix it? I dont want to add height or any content to parent tag. I want height of parent element to auto-increase in accordance to content of floating elements? How can I achieve it?
you have different ways to manage floatting element and include them in the flow. Parents or aside elements needs their layout to be trigger in a way, it calculates room/space used by floatting elements.
here is a few ways that you can apply to your snippet :
/* different ways to play with layout */
.outerdiv:before { /* add classname in document to be abble to relat it to css rules applied , demo purpose */
content:attr(class);
position:absolute;
margin-top:-1.2em;
background:yellow;
}
.outerdiv { /* demo purpose , we stack them */
clear:both;
margin:1em auto;
}
/* here we go ========================================= */
.clearafter:after {
content:'';
display:block;
clear:both;
}
.displayib {display:inline-block;}
.displaytb {display:table;}
.overflowh {overflow:hidden;}
.overflowa {overflow:auto;}
.overflowv {overflow:visible;} /* defaut, doesn't trigger anything */
.float {float:left;}
http://jsfiddle.net/Xq2We/1/ you can see each possibilities and see what it involves as result.
To go further and understand better you can read this : http://css-tricks.com/all-about-floats/
add
#parent{
overflow:auto;
}
or clear floats using available techniques

How to invert my <p> order in a div in CSS2?

I need your help: I want to reverse the order of <p> elements that are inside a <div>.
The difficulty is that I can't change the HTML, I can't give a class at each p, I can't use CSS3, and I can't add any JavaScript.
I can only make changes to the CSS.
<div id="divID">
<p>1</p>
<p>2</p>
</div>
CSS is for styling, not ordering your markup... but that being said, with CSS3 you can rotate the DIV and then individually rotate the P elements which will make them appear "in reverse order".
This is not very accessible, something like a screen reader WILL read your page differently.
http://jsfiddle.net/kzWr8/
div#divID {
transform:rotate(180deg);
-ms-transform:rotate(180deg); /* IE 9 */
-webkit-transform:rotate(180deg); /* Safari and Chrome */
}
#divID p {
transform:rotate(180deg);
-ms-transform:rotate(180deg); /* IE 9 */
-webkit-transform:rotate(180deg); /* Safari and Chrome */
}
Update: CSS2 Absolute positioning with sibling selectors: http://jsfiddle.net/kzWr8/1/
This assumes you know the height and number of a fixed number of elements so that you can position them absolutely.
div#divID {
position:relative;
}
#divID p {
border-top: 1px dotted #CCCCCC;
padding-top: 20px;
height:40px;
text-transform: uppercase;
}
#divID > p {
position:absolute;
top:60px;
}
#divID > p + p {
position:absolute;
top:0;
}
Short, technical answer: it's not possible. However, what is possible is changing how the order is displayed.
CSS is exclusively to style the webpage and nothing else. Changing the HTML directly will change the order. You could also accomplish such a thing with Javascript. However, CSS will only make it appear that the paragraphs have changed positions. This comes with consequences. For one, crawlers like search engines won't notice the change in positioning. Additionally, screen readers will most likely read it how it is in the HTML making the page very confusing for someone trying to access your page.
If you're okay with not actually rearranging the paragraphs, but instead making it appear like you did, you should probably check out how floating elements will make them appear in different positions. To my knowledge, this will only work in certain situations unless you want to reposition elements using relative and absolute positioning.
For example, if you've got two of the elements next to each other using floats (i.e., columns or links), it's pretty simple to float them to opposite sides (example):
.first-element { float: right; }
.second-element { } //whatever
As pointed out by #artSx in the comment below, I realize you may not be able to add a class in your HTML. If there aren't already any classes or IDs that differentiate the two elements, you'll have to read up on different types of selectors (like nth-child and so on).
However, if you wanted to completely reposition the elements relative to the page or a parent div, you may want to read up on how absolute/relative positions work and how they'll affect the flow of your page.
There are likely multiple ways to achieve this. We'd need some legitimate examples of what you're trying to do in order to give you the method that works best for your situation.

Division of percentage dependent on number of columns

I'm styling up a bar chart. There are potentially unlimited bars and I need them each to have a proportional width to their parent container- currently I have something like:
.one-column {
width: (100% / 1);
}
.two-columns {
width: (100% / 2);
}
.three-columns {
width: (100% / 3);
}
etc
... which I would add to each bar.
Can anyone think of a clever way of getting around this and just having one rule that could handle unlimited columns - maybe something to do with data attribute?
With some tricky combinations of CSS3 selectors you could find out how many columns are in use and dependent on that style the width of the containers:
div:first-child:last-child {
width: 100%;
}
div:first-child:nth-last-child(2), div:last-child:nth-first-child(2) {
width: 50%;
}
div:first-child:nth-last-child(3), div:first-child:nth-last-child(3) ~ div {
width: 33.33%;
}
div:first-child:nth-last-child(4), div:first-child:nth-last-child(4) ~ div {
width: 25%;
}
As you can see, you will still need to add a rule for every possible number of divs, but you don't need to detect anymore how many divs are there and to set classes accordingly.
But there is also another possible solution in your case. You could use display: table, display: table-cell etc. on the divs and the parent element in an appropriate way. Then if you set the width of the parent to 100% and the width of the containers to all the same value (e.g. 1%), you will get exactly what you wanted to.
Have a look at LessCSS - it supports mathematical operations. Otherwise I'd recommend you use Javascript to handle the styling of your bars. Perhaps use a graph library like Raphael?

Is it possible to set the width of a set of elements to add up to 100%?

Probably not the best title I've ever written, but I find it hard to formulate this question well. I'm working on a div that should cover 100% of the parent (could be body). This div should have a variable number of children, so every time the page is refreshed the children count can vary from one to ten, maybe more.
I want these children to all be equally wide and have a percentage width. So if there are five children, each child should have width: 20%. If there are two children, they should have width: 50%. I could do this with JavaScript, but I'd really prefer keeping all layout stuff in the css.
Is there a way to accomplish this without using tables?
Use display: table, display: table-cell, and table-layout: fixed.
See: http://jsfiddle.net/thirtydot/ZKXrM/
table-layout: fixed is to equally distribute the available width between any cells without an assigned width.
This works in all modern browsers. It doesn't work in IE7. If you need this to work in IE7, either use JavaScript to polyfill, or use a real <table>.
CSS:
.container {
display: table;
table-layout: fixed;
width: 100%;
}
.container > div {
display: table-cell;
border: 1px dashed red;
}
HTML:
<div class="container">
<div>1</div>
<div>2</div>
..
</div>​
You could define something like
div#contains2 div
{
width: 50%;
}
div#contains3 div
{
width: 33%;
}
and so on, then apply the appropriate class to the parent div.
That said, is there a good reason why you're avoiding a table, but trying to recreate how a table works? Sure, it may not be the absolute nicest "sleep-well-at-night" way to make a page, but if the table does the job how you want it doing, and you can't think of anything else that does, go with the table.
The bottom line is that you have essentially 3 options for automatic same-width columns:
Tables, which do it out of the box and will work cross-browser with no major issues
jQuery, which will probably work cross browser, provided the user has JS enabled
CSS like I suggested above, which adds bloat to your CSS file, and fluff to your markup
You can divide the total width (100%) into the number of items (X). So W = 100/X and W=Width.

Resources