I am working with a page layout that has a sidebar/callout box that's floated to one side of a large chunk of text content, and the text content may have some notice banners with a different background color sprinkled throughout.
Here is the issue (full JSFiddle here):
Undesired:
As the text in the mockup says, note the pink "notice" banner is overlapped by the yellow sidebar (margin only kicks the text back, not the edge of block elements that overlap it). I would like it to look more like:
With the pink background stopping at the margin of the sidebar. I was able to accomplish this in the mockup by setting a width of the notice banner (because I knew it would intersect the sidebar), but if that notice appears further down the page, it wouldn't expand to the full width, then.
Is there some sort of structure/style that would let me accomplish this sort of appearance, and be flexible as to where the notice banner appears within the content?
You could simply add overflow: auto to your notice to stop its background from leaking behind the sidebar, while preserving the margin on the sidebar.
The reason this works is because overflow that isn't visible interferes with floats as it creates a new block formatting context. Usually, this results in the box simply not intersecting the float (and its margins, if any). Keep in mind that, due to this, if any part of a notice box would otherwise intersect the float, this would cause the entire notice box and its contents to be restricted to the narrower width. You can see this by adding/moving text in the surrounding paragraphs and the notice box itself (I can't easily demonstrate this with a fiddle link).
The spec has this to say, in section 9.4:
In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box's line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).
Which points to section 9.5:
The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space. They may even make the border box of said element narrower than defined by section 10.3.3. CSS2 does not define when a UA may put said element next to the float or by how much said element may become narrower.
While the second quote sounds daunting towards the end, the behavior you see here is quite consistent, and not an edge case where you would start to see deviations in implementation.
You can be clever, and use a white border to hide the contents behind it.
Like this:
.sidebar {
border-left: 1em solid #FFF;
}
Example: http://jsfiddle.net/UrsLW/7/
And the result:
enclose your SideBar with another wraper
HTML:
<div id="test">
<div class="sidebar">
</div>
</div>
CSS:
#test
{
/*moved from your old siderbar*/
float:right;
width:40%;
padding-left:1em;
/*essential*/
background-color:white;
}
.sidebar
{
padding:1em;
background-color:#FFC;
}
look here: http://jsfiddle.net/UrsLW/11/
First thing that came to my mind was using CSS3's box-shadow, maybe?
.sidebar {
float:right;
width:40%;
padding:1em;
margin-left:1em;
background-color:#FFC;
box-shadow: 0px 0px 0px 1em #fff;
}
Or even a simple border would work, for that matter.
.sidebar {
float:right;
width:40%;
padding:1em;
margin-left:1em;
background-color:#FFC;
border: 1em #fff solid;
}
This would work only with single-colored backgrounds, of course.
http://jsfiddle.net/UrsLW/5/
Related
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.
In the CSS code below, it appears that the background of divTwo has moved behind divOne. But the content of divTwo appears to have been left behind - why does the background of the div appear to move independently of the content?
#divOne {
width: 300px;
height: 100px;
background-color: yellow;
margin:5px;
float:left
}
#divTwo {
width: 300px;
height: 100px;
padding:5px;
background-color: green;
}
<div id="divOne">Div01</div>
<div id="divTwo">Div02</div>
result in Chrome
The content of divTwo is not moving independently. The content is text, so it's rendered in a line box.
Now while unfloated, uncleared blocks ignore the presence of floated elements that precede them, the line boxes that they contain don't. The line boxes will avoid the floated element and go either alongside the floated element or, if there's no space for them there, underneath the floated element.
In your example, there is no space alongside, so the text has gone underneath the floated element. But since you've set a fixed height for divTwo, there's not enough space underneath and yet inside divTwo for the line box either. So the text content overflows divTwo, hence the text appears without divTwo's background behind it.
From Mozilla provided Float Documentation
How floats are positioned
As mentioned above, when an element is floated it is taken out of the
normal flow of the document. It is shifted to the left or right until
it touches the edge of its containing box or another floated element.
So I imagine when you declare float for divOne but not divTwo, then divTwo is following the normal flow of the document which is the same position as divOne.
You may also find Documentation for CSS Display useful.
If you do want these inline, but do not want to declare float for divTwo you can use:
#divOne {
width: 300px;
height: 100px;
background-color: yellow;
float:inline-start;
}
#divTwo {
width: 300px;
height: 100px;
padding:5px;
background-color: green;
}
This is something quite frequently met in just simple HTML. In you current code, you are not using any containers, wrappers or rows. This leads for the elements to overlap, if you want them not to overlap, you should give them some positioning or padding. In the provided fiddle, I have added a padding of 50 px for the divTwo in order to increase it's box show it is seen better.
The main idea is that you never start simply writing code but carefully think about the positioning of each element on your webpage. A good practice would be to learn how to "stack" elements( That's how I call it, the term might not be correct). Another thing is that there are some certain front end frameworks which could teach you better by example how to do this.
Bootstrap, Zurb Foundation (But Bootstrap...I'm not sure how many people use Zurb)
Here's the JS Fiddle to see how exactly the div has changed:JS Fiddle
Like #ZobmbieChowder said, the logic of CSS float property is that you have a huge box which contains two smaller boxes, and now you want one is located on the left and another on the right. If you don't have the huge box first, the complier doesn't get human's logic which one shall be the left or right. It only makes sense for machine that you "define" a container first, then talk about its element position left or right.
Alternative to #jpat827 answer would be to either set div two's clear property to left or add an empty div after div one and set it's clear property to left. What
The clear property, if there is no space left for the unfloated element, prevents the unfloated element from going under the floated element.
When you clear the div two to left, then what it really does is that it places div two below the floated element.
let's say, div one was floated to right, then you would have to clear div two to the right, in order to bring it below div one.
If, there were three divs, out of which two were floated to left and right, then the clear property for the third unfloated div must be set to both so that it can clear past elements floated in either direction.
I hope this was helpful.
Thank You
I'm looking for a HTML/CSS solution to a problem we've encountered on a site we're building.
I am happy to implement a JavaScript based solution if I need to, but I'd prefer it was handled natively.
We have content managed text which needs to sit inside a designated area but wrap if it exceeds the available width.
Behind the text is a background colour with opacity.
When the text is short, due to the float, the container collapses to the width of the text.
When the text is long, and a wrap occurs, the container hangs out at the maximum width, even though the text inside has wrapped underneath, so there's a small section of background colour on the right side (which isn't big enough for the wrapped word)
I want the container to collapse to the edge of the previous word so it doesn't "look like" there is space for the wrapped word, when it is very close.
HTML
<div>
<p>Crack the Shutters Open Wide for Parkside Paradise</p>
</div>
CSS
body div {
background-color: #AAFF3B;
max-width:80%;
padding:20px;
display:inline-block;
float:left;
}
body p {
display:inline-block;
background-color: #FFAA3B;
position: relative;
float:left;
white-space:pre-line;
clear:left;
}
Here is a JSFiddle: http://jsfiddle.net/nmuot8bm/3/
If you look at the 3rd example, you can see a small amount of padding on the right hand side of the orange box, where the word porttitor has wrapped underneath to a new line but the orange container still sits at the maximum width, despite the float.
If line breaks are introduced by the content editors (e.g. between vestibulum and porttitor as per example 4) then the container collapses correctly.
What I think is happening is the container grows before the text wraps and the browser doesn't recompute the width after wrapping?
Here's a picture of my test case shown in the JSFiddle:
Here is a picture of the fault on the staging site (before separated out to a JSFiddle):
You can see that the text has wrapped, but the container has not collapsed, leaving a big gap of background colour.
n.b. We can emulate this by doing text-align:justify but then the spacing between the words is not consistent with the rest of the text on the site.
edit: I see that this question may be a duplicate. I swear I did research before I posted!
max-width adjusts to fit text?
CSS Width / Max-Width on Line Wrap?
Wrapping text forces containing element to max-width
Shrink DIV to text that's wrapped to its max-width?
I think that the general consensus/conclusion is that it is not possible without bleeding edge CSS and I should use a JavaScript solution.
I have added a few more examples to my JSFiddle: http://jsfiddle.net/nmuot8bm/6/
including the JavaScript solution from here: https://stackoverflow.com/a/33246364/647728
Not possible with CSS...that's the way the inline box model works
JS example/solution can be found on the JSFiddle
If the problem is floated elements collapsing the parent container, there are many solutions; the easiest among them being adding overflow: hidden or display: table to the parent (the thing collapsing). Also be aware that inline-block and floated elements are essentially redundant.
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).
So first a bit of meat to set the scene:
HTML
<div id="container">
<div id="inner">test</div>
</div>
CSS
#container {
width:300px;
height:150px;
background-color:#d7ebff;
}
#inner {
width:100%;
height:100%;
padding:5px;
background-color:#4c0015;
opacity:.3;
}
This will produce something that looks like this in all modern browsers:
Now I know this is the standards-compliant behavior (as I knew before, but reconfirmed in this post, and I also know that if I include this code in the inner CSS declaration:
box-sizing:border-box;
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box
...it will adopt the "border-box" model and get the behavior that seems more intuitive to me, but I just found myself trying to logically justify the reasoning behind why this is the way it is and I was unable to do it.
It seems (on the surface of things) more logical to me for the inner box to always fill the container to exactly 100% of the container's width, regardless of the padding or border of the inner box. I run into this problem all the time when I'm trying to set the width of a textarea to 100% that has a border or something like a 4px interior padding...the textarea will always overflow the container.
So my question is...what is the logic behind setting the default behavior to ignore the border and padding of an element when setting its width?
The reason CSS uses the box model as:
+---------------------
| Margin
| +-------------------
| | Border
| | +-----------------
| | | Padding
| | | +---------------
| | | | Width x Height
Is because CSS is a document styling language. It was (originally) designed with research papers and other formal documents in mind, not as a way to make pretty graphics. As such, the model revolves around the contents, not the container.
CSS isn't a programming language, it's a styling language. It doesn't explicitly tell the document how it should be displayed, it suggests some guidelines the browser should follow. All of these can be overwritten and modified by an actual programming language: JavaScript.
Going back to the content-model idea, consider the following CSS:
p
{
background-color: #EEE;
border: 1px solid #CCC;
color: #000;
margin: 10px;
padding: 9px;
width: 400px;
}
height isn't specified, because the content defines the height, it may be long, it may be short, but it's unknown, and unimportant. The width is set to 400px because that's how wide the content (text) should be.
The padding is just a means of extending the background color so that the text can be nicely legible away from the edges, just like how you leave space when writing/printing on a sheet of paper.
The border is a means of surrounding some content to differentiate it from the other backgrounds, or to provide a border (go figure) between various elements.
The margin tells the paragraph to leave some space between edges, and with margin-collapsing, each group will remain evenly spaced without having to specify a different margin for the first or last element.
To maintain fluidity, width defaults to auto, which means the width will be as wide as possible:
without squishing the content unreasonably
without the padding extending beyond its container
Of course, in edge cases, the padding will extend beyond its container because the content might get squished. It's all about the content.
You might want to review the following at w3c: http://www.w3.org/TR/CSS21/box.html
The box model is such that the height and width pertain to the content area of the element. Padding is outside of that area which is why you see the inner box overflowing the outer one.
After padding comes the border, if any. Then Margin applies outside of the border. This means the elements actual width is defined as: Width + Padding + Border + Margin.
In effect, the css you have defines the inner box to have a 300px by 150px content area plus an additional 5px of padding beyond that which yields a box that is 310px by 160px.
Personally, I agree that the Width should include the padding. However, that isn't what the spec says.
As a side note, quirks mode does include the padding (and border) in the actual width. Unfortunately, quirks mode screws up so many other things that it's usually better to just deal with the w3c spec'd model than try and create all the css necessary to fix the other "quirky" things.
Another site (who agrees with you and I) is here: http://www.quirksmode.org/css/box.html
They mention that CSS3 includes the box-sizing declaration (as you've found) which is supposed to give you more control over which box model to use. It looks like just about everyone (IE8, chrome, Firefox) supports that which is good.
To answer your question, I think the logic is that it is all about the content; if you specify dimensions, these are the dimensions that the content is going to get.
But in the end it is just a choice that was made and that´s what we have to work with.
Look at the following picture:
Now consider what happens when you set the values width and height to 100% - should the padding and border just magically disappear from this picture? How would you as a developer ever handle that in a reasonable way?
width and height is width and height, border and padding is something else - to me it does't get anymore logical than that.
On the other hand
width and height is width and a height, but sometimes when you choose to set them to 100% they are also border and padding - now that would make no sense to me.
But then, one mans logic can be another mans nonsense, so i don't know if this will help you ;)
Although this may not have been an original intention of the CSS box model, another benefit is if you want something with an offset background image (e.g. the image is to the left or right of the text). Then you could specify the padding to be the width of the background image so that the text does not overlap it, and still specify a width for the text itself. For example:
.imageDiv{
width:200px;
background-image:url('someimage.png') /*this image is 50 px wide*/
background-repeat:no-repeat;
padding-left:50px;
}
Now any text entered into a div with the class imageDiv will show the image to the left of the text with any overlap.