Negative Left Margin issue and Mysterious 4px difference - html

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...

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.

Why display=inline-block adds uncontrollable vertical margins

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)?

Chrome - Box shadow on :active causes bottom padding to disappear

I suppose the best way to show this is in an example: jsFiddle here
Notice that the container (.overlay_inner) with the black border has padding on all sides. If you click on the button in the top right labeled "select" the container's bottom padding disappears!
This strange behavior only occurs for me in Chrome (version 13). I don't see it in IE or Firefox.
I've sort of narrowed the problem down to this block of CSS:
input[type=button]:active {
background: -webkit-linear-gradient(top, #eaeaea, #e2e2e2);
box-shadow: inset 0 0 3px #aaa;
}
Relevant part is the box-shadow. When I remove that bit of CSS, the problem doesn't occur. Doesn't make sense to me, though. Any thoughts?
EDIT: Potential work-around found. I removed the container's bottom padding and added a placeholder div at the bottom with a height equal to the padding amount removed.
Example: jsFiddle here
Feels really hackish which makes me uncomfortable since I thought I left that behind when I stopped writing for IE, but oh well ¯\_(ツ)_/¯
I managed to minify the test case to this: http://jsfiddle.net/4GfWY/8/ and I found that the requirements for this bug to occur are:
You must have a block with
overflow: auto;
position: relative;/* Or on any other block in this but over absolute one */
padding-bottom: 100px;/* Any bottom padding */
Some content that would cause a vertical scrollbar.
An inner block with position: absolute.
And if you'd then change box-shadow for this inner block, the bug occurs.
So, there can be a lot of workarounds, the best I think is: http://jsfiddle.net/4GfWY/9/
There I replaced the position: absolute to float: right (and made some other corresponding changes ), so:
One of the requirments for bug is gone, and the bug itself is gone.
If you'd have a lot of text in title, you could make it wrap: http://jsfiddle.net/kizu/4GfWY/10/ (I replaced there height to min-height), so the button wouldn't overlay the title's text.

How to make height squeeze with css

I've got an example mht file here that will help demonstrate my issue; if you are using FF then this addon will help you view the mht file. You will prob need to download the file and view it locally since github doesn't provide the right mime type for the file.
Basically my issue is this that I have a div which is 32px in height surrounding another div which is 29px in height, and I have no idea why the former is 32px tall.. It should be 29px tall afaict.. I don't want to set height:29px tho because if you resize the window so that the nav items take two lines then the height shouldn't be 29px for either div.
So what is wrong here?
make the following changes-
(-) to make your ul and wrapper div bottoms to align change class #navigationSecondary ul.base
to have a display:table; instead of display:inline-block;
(-) to remove the 3px of blue at the bottom change class #navigationSecondary to have padding:0; as sugested by Marcel.
the use of display: inline-block; on the ul.base is the cause.
when you use that it formats an element like it were inline (it only formats the actual content of the element like a block), so ul.base will have the usual 2-3px top and bottom "padding" that a normal inline element has. It's not really padding it's the leading vertical spacing i.e. it's what gives lines enough space to provide for the ascenders and descenders of letters like g, h, p, etc.
the use of it here is to make it seem like your ul is containing the floated child list elements. To make an element contain it's floated children there are other ways to do this, one way is, on ul.base
remove: display: inline-block
add: overflow: hidden;
[UPDATED] re the tabs.. sorry I didn't see them before I started
Here's the "float everything" solution to containing child floats as it applies to your code, with some other suggestions too
.menuContainer all it needs is position:relative; and the border-right rule
.navigationSecondary float it left with a width of 100%; (you can remove z-index it's not doing anything)
.wrapper float it left with a width of 100%, remove the height
ul.base doesn't actually need anything but remove the display-inline-block.. it's not containing the child lists but there's no effect involved, if you want to you can float it left with a 100% width too
[UPDATE 2]
I just copied this to a plain HTML document and I think that just changing the DOCTYPE to an HTML4 transitional one solves the problems with no changes to the code ?? (why that should change the display be I don't quite know! - but the use of "target=_parent" is "not allowed" in Strict Doctypes so that'll be why it's not validating)
I'll put it in JSBIN so others can try it out on various browsers
I changed it to:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
jsbin (with original HTML5 doctype) is here http://jsbin.comhttp://jsbin.com/agihe5/2/ - shows gap
jsbin with changed Doctype - but no changes to CSS code - with flash video to show dropdowns are working is here : http://jsbin.com/inare6/2 - no gap!
jsbin with no changes to Doctype, suggested changes to code and the flash insert to show z-index working is here: http://jsbin.com/iriya4
with the latter, code changes are detailed in the source, they have moved to the bottom of the snapshot CSS
I've tested the changed Doctype version as working in IE7, IE8, FF3.6.15, Safari4 (Win) and Chrome
Providing a test case which requires me to use Firefox and download an extension to view it is highly annoying.
I just did it anyway (purely because of the bounty), and the only change you need to make to your test case is:
On #navigationSecondary ul.base, add vertical-align: top.
The extra height is gone.
Here's a demo based on #clairesuzy's demo titled "jsbin (with original HTML5 doctype)".
(The only change was adding the aforementioned CSS rule):
http://jsbin.com/agihe5/3
The other answers may work (I didn't test them), but (providing I've understood the issue properly), this is by far the easiest fix.
Apparently #navigationSecondary has padding:0 0 3px; set in unnamed-1.css on line 2.
Everything inside ul.base has a height of 24px. Itself has a padding of 2px. So it's height is 26px. It's parent div.wrapper has a height of 29px, 3px extra. It's not caused by the 3px padding of div#navigationSecondary. Nothing is contributing the extra 3px so I'm suspecting a float issue. Anyway I managed to fix it by floating 2 divs.
Add float: left; width: 100%; to div.wrapper and div#navigationSecondary.
Remove display: inline-block; from ul.base.
Floating div.wrapper and div#navigationSecondary collapses them to their nearest floated child element, in this case li.base, and removes the extra 3px. 100% width brings back the stretch.
Hope this helps.
<body style="zoom:0.99; -moz-transform: scale(0.99); -moz-transform-origin: 0 0;">
adjust accordingly, and change hight and width around
Of course. This is simple. A very elementary element positioning issue.
inline-block default vertical-positioning
ul.base is an inline-block. which means that it has spacing calculated like a block, but positioned like an inline-element.
The default positioning of inline-element is to align on the baseline of text. However, text goes below the baseline for letters such as g, j, q etc. This is called "descenders".
The height of a box is always from the top of the font to the bottom of the descenders.
The wrapper takes on the height of its children. Which means that the inline-block ul.base, positioned on the baseline.
Your font at that particular size happens to have a 3-pixel descender. Voila. Your mysterious 3-pixel gap is merely the text's descenders. And your inline-block element is positioned on the baseline (i.e. on top of that 3 pixels).
Tests to confirm that this is right
Change font size. You'll see that 3-pixel changes. Change font size to small enough and it'll reduce to a 1px descender. Your so-called "gap" will shrink.
Change ul.base to something other than an inline-block (of course you have to add something to clear the floats inside). It will no longer have the 3 pixels at the bottom because a non-inline element is not positioned on the baseline.
Position ul.base on the absolute bottom instead of the default (baseline). That 3-pixel gap disappears. Use this CSS rule: vertical-align:bottom
Morale of the story
You always have to be careful with baseline positioning whenever you use inline-block display style.
Off topic
Handling font descenders is especially frustrating with Asian languages. As you know, CJK languages do not have characters that go below the baseline. However, they are typically placed on the baseline (so that they can inter-mix with other European languages, which have descenders). However, when one places a block of text with a background containing only Asian characters, the text will look like it is moved to the top, with an ugly empty gap on the bottom (the descender).

IE CSS Fieldset border extends too far to the right: Why?

I have defined a fieldset in HTML, and applied the following (simple) CSS rules to it:
fieldset
{
margin: 2em 0;
position:relative;
padding: 1em;
border:1px solid #ccc;
}
Everything is great, no big deal, except in all versions (well, up to 7 as far as I know) of IE the top border -- but not, interestingly, the bottom border -- of the fieldset visually extends too far to the right by about 25px, beyond where the vertical border is on that side.
It is worth noting that this element's width causes it to be outside its parent element width-wise to the right, when viewed in Firebug for example.
What is causing this problem in IE? Is this a known issue, and, if so, what is the fix / hack / workaround?
I've struggled with this one for some time; tonight I finally found the answer.
http://www.sitepoint.com/forums/showthread.php?t=526881
To quote NatalieMac:
Seems that if you have an element inside the fieldset that's overflowing
to the right of the fieldset, it extends the top border. I had a
container set to a width of 100% with no padding or margins which IE7
thought was overflowing for some reason (even though the content inside
this container was right-aligned and viewable within the border of the
fieldset).
I was able to fix it just by adding overflow:hidden to the fieldset.
I can confirm that this does indeed fix the issue for me as well.
Could you post more of your code, like the HTML of what's surrounding the fieldset and the corresponding CSS rules for that?
You mentioned that you can see it's wider than its parent element in Firebug. That's almost certainly related. Can you change the CSS of the parent element to make it wide enough to contain the fieldset?
Without a little more context, it's probably going to be tough to diagnose this more accurately...