Why display=inline-block adds uncontrollable vertical margins - html

I'm trying to fiddle my problem on http://jsfiddle.net and have got strangest behaviour there. Can you please explain where these (http://jsfiddle.net/C6V3S/) vertical margins come from? Does appear on jsfiddle.net (at least in Chrome and FF), do not appear when copy/pasting to local standalone file ...
works OK afer changing to simple block
Sample for standalone test file:
.btn {
padding: 0px;
border: 1px solid red;
display: inline-block;
}
.txt {
display: inline-block;
width: 12px;
height: 12px;
border: none;
padding: 0;
margin: 0;
background: #77FF77;
}
</style>
<div class="btn"><div class="txt"></div></div>

When you make the .txt element inline-block, it is taken into the text flow of the parent .btn element. At that point, the line-height of .btn kicks in, which is larger than the height of the .txt element.
So, add .btn {line-height: 10px;} (for example) and your problem is fixed. I saw you already tried to influence the line-height of the inner .txt element, so you were pretty close with your attempts. Adjusting the font-size would work as well, since the default line-height is formula-based on the font-size. Anyway, the key is to do that on the parent element, not the child element.
You don't have this problem when you make the inner element a block, because then there's no text-like content, so there's no line-height applied at all.

inline-block is brilliant and convenient for so many cases. But they come with one annoying pitfall: unnecessary whitespace. As you're nesting an inline-block within an inline-block, that results in a white-space disaster. You can read all about whitespace and inline-blocks on David Walsh's blog.
There are many ways to handle this, but my favorite (and most widely supported) solution is setting this to the parent inline-block element:
.btn {
font-size: 0;
}
Here is an example of before/after:
http://jsfiddle.net/C6V3S/1/

This is not caused by whitespace (you don't have any inside the divs in your HTML), nor by putting inline-block inside of another inline-block. This is caused because of the line-height of the outer div. As you can see from the below fiddle, the current line-height of the red-border div has a line-height that is being set by the browser (and it varies from browser to browser), and as long as there is something inside of the div that takes up space as an inline or inline-block item, the height will be affected by the line-height.
There are many ways around this, and they all pretty much do the same thing:
1) Take the inside element out of flow, and then reinsert it back in. This will make the outer div think that there is nothing inside of it, and try to become as small as possible, and then fill up space exactly around the element when it inserted back in. The easiest way to do this is by floating it.
2) Make the outer element take up no space. This will make the inside element define the height and width of its parent. If you do font-size: 0, as mentioned before, this will make the outer element think that the inline inside element takes up no space, and therefore not take up any space itself, and wrap itself tightly around the inner element. This can be done by setting line-height: 0 as well (which is a perfect fix for the problem, as the problem is line-height).
There are other ways to make the parent element not have its line-height, but that should get you started.
http://jsfiddle.net/C6V3S/4/

It's "just how it works," but it can be worked around. The easiest way to fix it would be to set negative margins on .btn. It should work for any modern browser (IE8 and above, if I recall). Floating the elements should achieve what you want, too. As a wholly different solution if your problem with it is merely aesthetic, you can just wrap the elements in a parent, set that parent's background-color to what you want, and not worry about its child elements' backgrounds. They'll be transparent to whatever is beneath them, and you'll get rid of those visual breaks.
If you want to stick with negative margins on with display: inline-block, but need that pesky first element not to jump leftward out of its parent, you could target it explicitly:
.btn {
margin-left: -4px;
}
.btn:first-of-type {
margin-left: 0px;
}
Edit: After reading another answer, I'm not sure if I understood the question -- do you mean the margin atop the elements (which would be horizontal) or the margin to the sides (vertical)?

Related

Floated element "steals" width from a following block element inside a display:table container

I have a div that's "floated" to the centre with display:table; margin:auto; (green box)
Inside this, I have a float:left element (red box, which is not always present), then a number of display:block; "lines" (lime boxes). The application is poetry formatting with drop capitals and reverse indentation:
https://jsfiddle.net/nktj94gd/2/
The problem is that the floated "L" is "stealing" its own width from the lime blocks, rather than allowing the outer block (green) to expand to prevent the lime lines wrapping when they do not have to.
I'd really like to avoid having lines wrap when they don't have to, but I cannot set the width of the overall box (it could be from a few em to 100%) .Is there a way to achieve this?
I would use an extra wrapper inside that I make slightly bigger considering the width of L
.outer {
display: table;
margin: auto;
overflow:auto;
outline: 1px solid green;
}
.outer > div {
width:calc(100% + 2.8em); /* 2.8em is an approximation of L width */
transform:translateX(-1.4em); /* rectify the centring */
}
.dropcap {
float: left;
}
.dropcap-inner {
font-size: 4em;
line-height: 1em;
margin-right: 1em;
border: 1px solid red;
}
.line {
display: block;
text-indent: -4em;
margin-left: 4em;
border: 1px solid lime;
}
<div class="outer">
<div>
<span class="dropcap"><span class="dropcap-inner">L</span></span>
<span class="line">orem ipusm dolor sit amet</span>
<span class="line">Lorem ipusm dolor sit amet dddd</span>
</div>
</div>
you probably found some more practical solution to this a year ago, but this is a fairly obscure problem I ran into while also styling poetry, so I figured I'd post my solution in case anyone else needs it :) Hope your poem project worked out, OP!
I think probably most people use <br /> and ::first-letter or something and thus never run into the problem. It's ultimately just a problem of how to preserve intended whitespace (linebreaks mainly) with a pretty dropcap, which is niche, but falls apart quick if you're designing responsively and avoiding hard breaks. (I was using whitespace: pre because it had indented stanzas) ¯\_(ツ)_/¯
How to fix OP's issue: table CSS and wrappers (responsive, markup-dependent), see: https://jsfiddle.net/eja5mnuk/
Stick the spans and the float in a container div
Change display: block on the spans to display: table-row; since your outer is display: table, and you don't impose widths anywhere here, the 'table' will simply expand to accommodate both the float and the linebox
Optionally, display: table-caption on an inner part of the dropcap (not truly necessary, but in OP's code so why not: https://jsfiddle.net/thn2x5zc/)
Everything is integrated into a table formatting context, but we aren't getting unwanted collapse that messes up sizing
This is responsive and doesn't care what your drop cap is. It runs into overflow issues if the drop cap and poem are both too big, you can shove whatever behaviour you want on this bad case if you want (like overflow: hidden on the dropcap, controlling their whitespace/widths, etc....)
It does care about your container structure and margin collapse a lot, so if your code were different, you'd need a different display value, likely something putting table-row/table-cell on a block.
Of course this does have quirks relating to how browsers treat table elements by default, though - mainly auto-collapsed borders, like in a <table>.
Method #2: ::first-letter pseudo-selector, white-space: pre, margin/padding etc. (things other people might use) see: https://jsfiddle.net/3oghpj0w/
These things are all very janky/contradictory secretly, but since ::first-letter is a pretty standard way to style drop caps, and marking up/styling your lines individually may be inconvenient, it is how I ran into the problem lol.
If it's ::first-letter, we're using a block-level element to hold the poem text. The most basic way is just to apply width: min-content; to that block's container to get it to sort of take away the float's contribution (since it's larger). Then you can add padding-right to that container to re-accommodate borders, margins, etc. (If the margin between the drop cap and poem is 3em, add 3em back to the right.)
Fixes of this style do not re-integrate the float with the poem, so the poem will still have overflow issues. But it's sufficient for fixing simple alignment problems :)
Some notes
The float contributes size to the block e.g. via its margins - floated margins don't collapse, generally, which is part of our problem here. But the container won't expand for things out of flow, and thus the float pushes its siblings into overflow (poetry is highly sensitive to wrapping and whitespace)
Ultimately, most ways the browser can calculate the size of text wrappers ignore the float (it's out of flow); everything skews towards occupying space along the inline and block axis (horizontal/vertical, here), based on everything's sizing, margins, wrapping, and other inline/block contexts, ref: https://developer.mozilla.org/en-US/docs/Web/CSS/display
Tables are the ancestors of most responsive text framing
Sorry this is so long! A lot of conventional fixes break when you care about the shape of the whitespace and can't treat text as a block, which makes a lot of search results very inapplicable.

Any problems with using a pseudo-element to space paragraphs with CSS?

What I have done most of the time to space paragraphs (or paragraphs and other elements) is to use the ::before tag. For example
p + p::before {
content: '';
display: block;
margin: 20px 0;
}
That way, I can be really specific about my whitespace. For example, I could also do this
h1 + p::before {
content: '';
display: block;
margin: 10px 0;
}
That way I know how the space between each element behaves.
Is this good practice?
On most places I have read that margins and padding should be used exclusively, but I found that I depend too much on id selectors when using them.
On the same topic, if I were to use them, should I use margin or paddings? On some places I have read that margins are prefered, yet on others that padding should be used for typography. By typography I refer to the main body of text: titles, paragraphs, and everything it may contain.
Of course, I would like to avoid <div>s on my HTML code, trying to keep it as semantic as possible.
Is this good practice?
No, not really. That's sacrificing valuable pseudo-elements that could be used for generated content or other clever layout tricks (every element can only have one ::before pseudo-element at a time), to do something that can be done conventionally with margins on the elements themselves.
The typical practice for spacing paragraphs is to specify vertical margins on each paragraph and allow margin collapsing to do the rest:
p {
margin: 20px 0;
}
... because this is what margin collapsing was designed for: so authors can say, "There should be 20px of space between paragraphs", without them having to calculate how much margin each paragraph should have on either end. In other words, this is how CSS implements the concept of paragraph spacing as seen in word processors.
If you don't want this behavior, you need only specify either a top or bottom margin, and change the value of that top or bottom margin wherever it needs to differ. For example:
p {
margin: 20px 0 0 0; /* Equivalent to margin: 0; margin-top: 20px; */
}
h1 + p {
margin-top: 10px;
}
Using pseudo-elements for this is unnecessary.
On most places I have read that margins and padding should be used exclusively, but I found that I depend too much on id selectors when using them.
On the same topic, if I were to use them, should I use margin or paddings? On some places I have read that margins are prefered, yet on others that padding should be used for typography.
This is too broad to answer concisely, but I will say that margins and padding can be used together in some situations as they serve different purposes in layout.
That being said, whenever you find yourself wondering if you should use one or the other, as a starting point consider what they were designed for: margins create space outside an element (that can interact with other margins in various ways); padding creates space inside an element to give its children breathing room away from its content edge. Again, there are a number of situations where it's not so simple, but unfortunately it would be too broad to cover in one answer.
It's not clear to me what that hearsay refers to by "typography".
Using margins and padding in tandem under CSS would allow you to have more freedom of how much white space you want between your elements or borders. Use padding to determine how much space u want in between elements within a closed border such as div or a table, etc. When you want to deal with white space involving elements that aren't restricted to borders or a certain boundary, use margin. Both margin and padding allow you to determine how much space you want to the right, left, top, and bottom of the element of your choosing.

Weird margin differences between Chrome/Safari and Firefox

I recently designed a website (http://willryan.us/typefun01), mainly using Chrome while coding to test. I recently noticed that there are some weird things happening at the end of certain sections, (the gap after History, the overlap of Styles onto Anatomy).
I have a css reset in my stylesheet (not sure if that has anything to do with this), and I can't figure out what's causing this, and how to get the site to look like how it does when viewed in Chrome
The gap after History is due to:
#historyWide {
margin: 250px 80px 75px;
}
It could be remedied with:
div#content > div {
overflow: hidden; /* or auto */
}
You could also move the large top and bottom margins of elements inside the child divs of #content to padding on the child divs themselves. Anything will work as long as it's all contained by those child divs.
You're simply seeing the different ways that browsers handle imperfect layout.
If you want to avoid the gap after History you would want to use a padding in historyWide instead of a margin; the margin pulls aways elements while padding makes them bigger
On anatomy what's happening is that you're using the property "top" to modify #styles, this will move the element but the parent will reserve only the original space for the element. You will be better off working with margins and padding than with "top" if you have to keep a relation between the elements.
Lastly, i woulnt position elements with margins like you did with #stylesMono. I think you could better work with paragraphs to keep keep the vertical position and, from there, working with floats, margin and padding in the scope of the "p".

Negative Left Margin issue and Mysterious 4px difference

I am scratching my head for quite a long time and finally decided to ask for help. Actually I have a simple form with two inputs (field + button) and I want to bring button over field while wrapping the form to correct width of text field + padding.
I am using
margin-left: -31px
on button which is set width of 27px.
You can try it at http://jsfiddle.net/UfK6K/
and it appears
BUT when I set margin-left: -32px it breaks the layout.
http://jsfiddle.net/UfK6K/1/ and appears
Now if I change width of button to any figure and as long I keep margin-left within negative 4px difference it works but when it increases like in case of -32px it breaks.
I want to understand from where difference of 4px comes into play?
And Of course how I can move button bit more left over text field?
*It breaks in all browsers except Opera.
Well its a very tricky question that from where 4px comes from. I'll try to answer it.
When any element is set display to inline-block then 4px are found to be placed at right side of this element. Actually its the size a 'white space' takes, yes its actually a white space.
You can think of it as that inline-block element are separated by a white space and it usually takes 4px because in Opera it takes bit more (not sure about latest version though -- because different fonts render whitespace with different widths in different browsers the only font that renders a consistent white-space width across browsers and font sizes is Courier New. it is a fixed width font, and it’s whitespace is 0.63em wide.). But you get the point?
Now there are various work around like float:left or even setting negative 4px letter spacing of parent element which contains inline blocked elements.
You can also try font-size: 0;
And in your particular case position:absolute; seems to be best option.
You could add position: absolute; to the button's CSS.
.sbutton {
position: absolute;
margin-left: -30px;
margin-top: 1px;
/* ... */
}
Fiddle: jsfiddle.net/UfK6K/4
Not sure why it breaks (FF9 here). CSS positioning can cause lots of fun sometimes.
The 4px comes from the rendering of the white space between the two input fields. The button moves on to the next line because you're not leaving sufficient space for the white space to be rendered on the first line after the first input box.
The white space wraps to the next line and the button is then rendered after it, shifted by the margin-left setting.
As you've already discovered, removing the white space between the input box solves the problem. The alternative in CSS would have been to add white-space: nowrap; to the form styling.
Another way that you could do it is by adding
.sbutton {
margin-right: 5px;
margin-left: -32px;
}
and for some reason that fixes it. Then for every pixel-decrease in margin left, increase the margin right.
negative-margins have always confused me...

<img> positioning behavior

I can't seem to wrap my head around how img tags behave alongside text in an html page.
I've removed margins and padding, but there always seems to be some extra space under the img or some other unexpected behavior. I'm sure theres quick CSS workaround using absolute positioning or negative margins but I'm looking for a more general solution.
Question: Can someone explain how img tags are positioned, specifically why do they get offset vertically when alongside text?
If you want the <img> to be an inline element, you can use the vertical-align CSS attribute to specify how the image will be aligned relative to the line of text it appears in. This page has examples under the "vertical-align on inline elements" heading.
The key to getting your text to wrap around your image is setting the float attribute like so:
img {
float:left;
display:block;
}
CSS has two types of display: attributes: block and inline.
Inline is like text. It streams along, wraps at the end of a box, stuff like that.
Block is chunky and has margins and padding and width (either calculated or derived).
It doesn't make a whole lot of sense, but <img> is actually an inline element, along with <a>, <abbr> and many others. What's happening is that the image is actually being rendered roughly equivalent to letters, and it just happens to not be 12pt tall, but maybe 130px or whatever your image is. That's why it sticks up.
Declare <img style="display:block;" src="image.png" /> to get it to behave like the box most people think it is.
IMG elements get positioned just like any other inline element.
What you see under the img is the space needed for the descendant part of a glyph like g or j. An image behaves just like a letter and sits on the baseline.
img
{
display: block;
}
Will fix it for you.
An experiement that might shed some light:
<p style="font-size: 1em;">Lorem ipsum dolor <em style="font-size: 800%;">sit</em> amet.</p>
Think of the <em> as a ~128px high image (if 1em is 16px that is).
If you want more control over your image positioning, wrap your image in a DIV and control the positioning of the DIV. You can float the div if you want to intermingle it with your text.
This might not be relevant in this particular case (hopefully the advice from previous answers should solve your problem), but if you're finding you're getting unexpected extra space around elements, make sure that you've removed the default padding, margins etc. that browsers often add to elements (and of course different browsers often add different amounts of padding, margins etc.
If you make sure you've zeroed margins and padding etc. by using
body { margin: 0; padding: 0; border: 0; }
at the start of your CSS, you can then add any padding and margins etc. without having to worry that the browser's defaults are going to cause any unexpected spaces, and hopefully fewer inconsistencies between browsers.