Normalize perceived padding on an element with unknown children - html

I have a <div> styled like a box:
.box {
border:2px solid #ccc;
background:#eee;
padding:1em;
margin:1em;
}
In this box, there could be any number of any type of child elements in any order:
<div class="box">
<h3>Howzit goin</h3>
<p>Here comes a list:</p>
<ul>
<li>I don't know what</li>
<li>this box will contain</li>
<li>but it could be anything</li>
</ul>
</div>
Most or all of the child elements inherit bottom margin of various lengths from the base typography stylesheet:
/* Example global typography */
p {margin:0 0 1.5em;}
ul {margin:0 0 2.5em;}
Which produces output like this:
...but we want to normalize the "padding" of the box so that it appears equal on all sides:
.box :last-child would be too easy, this has to work in at least IE8 as well as
modern browsers (but it could be used in conjunction with an IE-only method).
I don't want to use extra markup or javascript.
Is there any other CSS trick I can use to get the output I want?
Fiddle: http://jsfiddle.net/yuXcH/1/

As you can read in this question, even if it's about 2 years old, there's no "easy" way to do this in IE8 (the other thread is just about IE6/7, but things haven't changed - IE8 doesn't support :last-child either).
The best way, in my opinion, is to manually add a class last-child to your last child so you can do:
.box .last-child{ margin-bottom: 0; }
The alternative is using javascript, which is easier if you have a lot of boxes. With jQuery, it would just look like this:
$(function(){
$(".box :last-child").css("margin-bottom","0");
})
The only "pure CSS" solution I can think of is changing all of your padding/margins to always result in a box with same padding on all sides like Lollero suggested, but this will, compared to your previous solution, result in different margins between the elements inside of the box.

I would probably compensate the extra space by having padding or margin in both top and bottom.
http://jsfiddle.net/lollero/yuXcH/2/
Also some padding change in top and/or bottom of the parent element can be used.
http://jsfiddle.net/lollero/yuXcH/3/

Related

CSS best practice between margin-top and margin-bottom when both can work?

What is the CSS best practice when you want to give space to an element placed just after a first element.
Asume this html
<div class="a-block">lorem</div>
<div class="another-block">ipsum</div>
Should you use this css
.a-block { margin-bottom: 10px; }
or
.another-block { margin-top: 10px; }
?
i would use :nth-child width margin-top
div:not(:first-child) {
margin-top: 10px
}
<div class="a-block">lorem</div>
<div class="another-block">ipsum</div>
<div class="another-block-1">ipsum</div>
<div class="another-block-2">ipsum</div>
In my opinion, margin-top in the second block is a better practice.
Indeed, the first div shouldn't take care about others divs since it was the first.
If the second is removed I shouldn't have to remember to remove margin-bottom from the first.
Using margin-top would eliminate the need of using a next sibling selector. It also removes the need of removing the bottom-margin from the last-child to avoid padding discrepancies when using text in panels or boxes.
Since nobody has mentioned it yet, I wanted to add that you could use both at once. This will cause them to meld together through a feature called margin collapsing. In certain situations this could as well be the best practice since you can use it to declare "this element need at least this much space below it". Note that margin collapsing may backfire on you if you accidentally use properties that disable it, such as floats, borders or flexbox.
.a-block {
margin-bottom: 10px;
}
.another-block {
margin-top: 10px;
}
div {
background-color: #e0e0e0;
}
.float {
float: left;
clear: both;
width: 100%;
}
<div class="a-block">Only 10px margin</div>
<div class="another-block">between these elements</div>
<hr />
<div class="a-block float">Double margin because</div>
<div class="another-block float">of the float</div>
It is completely up to the context in which the CSS is needed - is the short answer. It depends whether you need the first element pushed down as well as all the other elements. or you need the first element to be flush with the top of the parent but you need the bottom element to have a margin at the bottom.
The common sense thing to think is that the first element is already there so the second element will surely need to be "pushed" down, so the natural thing to do would be to add margin bottom to the previous element (at least that is the way that my brain works).
Current CSS browser support dictates that this is the preferred method. Due to the fact that, in CSS, there is a "next sibling" selector (~), an "adjacent element" selector (+) , and :first-child is more widely supported than :last-child is (purely because it is more difficult to implement in a browser than :first-child is). Namely this :last-child support issue is IE8 but this still affects us today when developing for certain clients.
There are no previous sibling selectors, so this makes me prefer the method of adding margins and paddings to the bottom of elements and not the top. Purely just to keep everything in my CSS to be using the same principal of "pushing things down from above or selecting the first element"
You should always be consistent on how you apply the styles.
For example, if you have a hero and think about the inside elements. For example, you have a title, optionally a button and optionally text below that. You can end up with having margins or padding that should not be there and were intended to have a button there.
Also, the point about collapsing margins is important when you have a design with different use cases. Padding doesn't collapse but if used improperly, can cause elements not to center 'properly'.

How to make more divs after each other non-wrapping, but the entire list wrapping?

I have divs after each other that look like this.
<div class="tag">one tag</div>
<div class="tag">second tag</div>
<div class="tag">third tag</div>
...50 more of them....
(in CSS)
.tag {
display:inline
}
I found out that I have too many of them and they start breaking in the middle, and I don't want that.
However, when I set the nowrap like this
.tag {
display:inline;
white-space:nowrap;
}
all of them are on one line, making more than 100% of the window. I don't want that.
What I want: if there are too many of these divs on one line, the list of the divs can break, but the divs themselves don't. I just don't want to break the divs in the middle.
I hope I tell it clearly enough.
If I understand right, you want them to lay side to side, and then break to a new line when the row is full, but not in the middle of a div.
All you need is
.tag {
float: left;
}
See fiddle here for demo.
You can also add padding-left: 5px; if you want some space between them.
.tag {
display:inline;
white-space:nowrap;
float:left;
}
That worked. (and adding "clearing" empty div with clear:both under that.)
Depending on the browsers you need/want to support, you may find using
.tag {
display:inline-block;
vertical-align:top;
}
a better solution. Since it is a <div> that you want to apply this to, the style will not work out of the box for IE5-7 - see http://www.quirksmode.org/css/display.html#t03. There are workarounds of course - How to fix display:inline-block on IE6? - if you want to use it with those browsers.
The benefit of inline-block is that you do not need to clear the floated content and also that your elements are not rendered out of normal flow. I try to avoid floating elements where possible as in my experience it has caused layout problems.
However, there are a couple of potential catches with this approach. One of which I have already addressed, by adding a vertical-align:top rule. See a previous answer for why this happens - https://stackoverflow.com/a/12950536/637889
The other is due to potentially unwanted white-space between the inline-block elements. See http://css-tricks.com/fighting-the-space-between-inline-block-elements/ for some clever ways around this.

CSS - IE7 ignoring margin on first list item?

If you go to the first blog item (Mona) and expand it using the '+' icon. The image thumbnails are aligned 24px from the left using a margin. This works in every browser but IE7 which ignores the margin on the first list item.
http://www.dririser.co.uk/index.php
CSS
.artistMeta li {
float: left;
margin: 0 0 24px 24px;
position: relative;
width: 160px;
}
There is a similar question on here but the there was no real answer and I can't use their solution.
Why is ie7 ignoring the left-margin on my first list item (only)?
Any ideas?
just a quick test.. not sure if it will work.. but try adding a display:block on your li and don't use the shorthand for the margin, instead use margin-left and margin-bottom...
it seems to me that IE is not refreshing the style of the elements, because when i inspect the elements, the navigator adds the correct margins...
If that doesn't work.. you might want to put the style inside the tag (since you're using JS to add the images), i know it's not elegant, but i guess that could force the navigator to set the style on the li
and if that doesn't work.. then i've no idea what could be wrong =P. I hope this helps...
Good Luck!
The problem IE7 is having here isn't in your CSS file, it's in your javascript in global.js. Specifically the following line ...
$(".artistMeta > li:nth-child(3n+1)").addClass("articleSlideOdd");
As per the convention in CSS, JQuery starts the child count at 1 for nth-child (as in the first child is nth-child(1)), where as, ie7 is expecting it to start at 0. So with ie7 3n+1 matches the 2nd, 5th, 8th item and so on.
Looks like JQuery isn't handling ie7 properly, so you'll need two statements to cover ie7, and everything else.

Could someone explain collapsing margins? I find them extremely annoying

I have a div that contains a link:
<div id="like_bar"></div>
With some CSS:
#like_bar{
width:140px;
height:26px;
background:url('bar.jpg');
}
#like{
display:block;
width:20px;
height:20px;
margin:3px 36px;
background:url('mini_img.png');
}
The link is placed at the top of the bar and the margins on the link are applied to the bar. This is annoying. Could someone explain these collapsing margins, how to avoid them and what they're used for.
There are many ways to "fix this".
Perhaps the easiest for you would be this:
#like_bar {
overflow: hidden
}
Other ways include:
Add some padding
Add a border (even border: 1px solid transparent is enough)
float the element
position: absolute
And, like in the snippet above, set overflow to a value other than the default of visible.
You also asked:
what they're used for
A common use case is the <p> tag.
See: http://jsfiddle.net/thirtydot/tPaTY/
Without margin collapsing, certain things would become annoying.
Because I'm lazy I'm just going to link to a few resources:
My answer here explains why the box model is the way it is, which is related to margin-collapsing being included.
The w3c css spec defines the behavior of margin collapsing. It's an expected behavior for convenience given the box model. You don't need to worry about double margins between blocks of content with it. What it sounds like you actually want is some padding around #like, rather than margins.
Think of CSS as a content-centric inside→out approach to styling, rather than a programmed outside→in approach.

Need to have spacing between end of div and beginning of paragraph

I have text within a paragraph tag that that fits snug on the bottom of a div, which you will see in this picture: http://i44.tinypic.com/e05s0z.png
I could put some padding at the bottom of the div to fix this, but there might be multiple divs, depending on how many items are on that page.
What I need to do, is put some spacing between the end of the very last div (class="article") and the text within the paragraph tag.
Here is the css for the article class
.article {
padding:10px;
overflow:auto;
}
Text w/i the paragraph tag
<p>Herkimer County Community College does not
discriminate on the basis of race, color, sex,
national origin, age, handicap, or marital status
in admission, employment, or in any aspect regarding
the conduct of College business.</p>
What should I do?
Give the final paragraph an id - #disclaimer, perhaps - then style that to have padding-top.
<p id="disclaimer">Herkimer County Community College does not
discriminate on the basis of race, color, sex,
national origin, age, handicap, or marital status
in admission, employment, or in any aspect regarding
the conduct of College business.</p>
and...
#disclaimer {
padding-top: 10px;
}
[EDIT]
An alternative to this, based on your comments, would be to surround the article(s) in a div, and give that div.class a bottom-margin/padding style.
If you have other paragraphs on your website and do not want to give it an id or class, then you can also use
.article + p {padding-top: 10px;}
Some old browsers will not be able to make out this selector, though
You could wrap your paragraph in a container that has padding at the top, so it doesn't matter what's above it.
For example, wrap it in a div with the following css
div.finaltext {
clear: both;
margin-top: 10px;
}
Here are your options as far as I see it:
Use the :last-child CSS3 pseudo
class to target the last div. This
isn't supported by IE at all, so
depends how important that browser
is to you whether this is an option,
but at least other browsers would
get the desired effect.
.article:last-child { padding-bottom: 20px; }
Add a class to the last div with the same style as above. This isn't ideal and may or may not be possible depending on how the divs are generated.
Add a class to the p tag with a padding-top value.
Use .article + p selector to target a p tag that is a direct sibling of .article. This is supported in IE7 (I think) but not IE6.
I would always give preference to #1 or #4 as it reduces clutter in the HTML, but as I mentioned IE could be a problem depending on your needs.
(thanks to Residuum for #4)
there is also the first-child and last-child css methods
note: check browser compatability for those you wish to support
It's the construction like this?:
<div class="article">jdhfksdjhfksdhk</div>
<div class="article">jdhfksdjhfksdhk</div>
<div class="article">jdhfksdjhfksdhk</div>
<p>kfdhsjkfdks</p>
You use padding: 10px so the div has 10px inside margin.
If it's a CMS, I'm sure that the text of the paragraph could be wrapped inside another tag (DIV) or maybe a class for the (P). If this isn't the case, may I ask if there's a surrounding wrapper around all of the article divs and the p tag?
If that's the case then you can get to the P tag using CSS, if not, there's no way you achieve this in every browser.
OR... I realized you could do a trick here. but you've got to be sure you have a selectable div on top of the article divs.
It should be something like this:
.article { margin-top: -5px; margin-bottom: 15px; }
so, every div.article will move 5px up, leaving 10px of real margin betwen article divs. but the last one won't have the -5px move up, so you'll end up with 15px bottom margin for the P tag.
You could play with the numbers to make it the most comfortable number. And in case you need more control, then use the padding values you set to 10px in every way and set them accordingly to compensate the margin offset.
Could you simply add a couple of <br/> tags after the last div?