I ran into an issue with absolute position with a nested p tag. This JSFiddle demonstrates the difference. Based on the description on this question and the comment by user1334007 absolute positioning is relative to the first parent. Even though w3schools does not state that, it appears to be the case for div tags. For p tags, it seems that absolute is relative to the page as Michael Zaporozhets states in the SO answer and w3school describes.
With all these links in mind, am I making a mistake with my styles somewhere or are these performing differently? If they perform differently, can someone offer an explanation as to why this happens please? The main reason I am asking is this is a question in the 70-480 certification tests and even though I know the answer the say is correct, I would like to be able to use positioning with confidence going forward.
Code in jsFiddle link (required to have code to submit jsfiddle link so i just put it all in)
<h2>Paragraph Position</h2>
<p class="outer">Hello Outer
<p class="inner">Hello Inner</p>
</p>
<br/>
<h2>Division Position</h2>
<div class="outer">Hello Outer
<div class="inner">Hello Inner</div>
</div>
.outer {
position: relative;
background-color: red;
height: 100px;
width: 500px;
}
.inner {
position: absolute;
top: 15px;
left: 15px;
background-color: green;
}
If you take a look at the HTML (I looked with Chrome Inspector), you'll see that p.inner isn't actually inside p.outer. Because of this, p.inner will be absolutely positioned relative to the first parent element that has relative positioning or the html tag (in this case the html tag).
Edit: I looked in Firefox as well and it seems as if these browsers will convert nested p tags into separate p tags. So a p tag inside of another p tag will result in three sibling p tags.
Related
Roughly speaking, attempting to build a four-column layout, I've got this HTML:
<div>
<div>A column</div>
<div>A column</div>
<div>A column</div>
<div>A column</div>
</div>
And I've got this CSS:
div {
background: #ccc;
}
div div {
background: #eee;
display: inline-block;
width: 25%;
}
-> Fiddle me this <-
When rendered in the browser (Currently, I have been testing with Chrome only) the whitespace between the nested div elements (in this example the whitespace is caused by line breaks) is rendered, thus throwing my layout out.
Clearly, I can float my nested divs...
div {
background: #ccc;
}
div div {
background: #eee;
width: 25%;
float: left;
}
-> Fiddle me that <-
But then my container div collapses and I don't want to have to have to use CSS clearfix hacks or extra HTML to open it back up.
Alternatively I can modify my HTML such that the whitespace is removed...
<div><div>A column</div><div>A column</div><div>A column</div><div>A column</div></div>
but that makes it hard to work with. The alternative of breaking the tags so that it becomes more readable somehow leaves me feeling dirty...
<div>
<div>A column</
div><div>A column</
div><div>A column</
div><div>A column</div>
</div>
I've found a resource or two (I failed to find anything on SO) but I don't really like any of the solutions - they are all workarounds, which I will entertain if I must but surely there's an alternative?
So my question(s)... is there a cross-browser, w3c-compliant, non-javascript, hack-free, tidy HTML, bombproof way of preventing HTML whitespace from being rendered in the browser whilst using display:inline-block? Or is there an alternative to inline-block that can be used that has no unpleasant side effects?
EDIT
Assuming that this is genuinely impossible, the best solution would be something that required no addition HTML markup and 'flexible' CSS. In other words, a webmaster could edit the HTML as normal without consideration of breaking the layout, and the CSS (hacked or otherwise) will accommodate the webmaster's amends without having to be amended itself.
MY "WORKAROUND"
Well, it looks like something's got to give. In my situation it is more important to have HTML that doesn't require extra markup so the best solution is to work in a CSS hack that "just works" invisibly. The solution is to float the nested divs and add a hack...
div div {
float: left;
}
div::before,
div::after {
content: "";
display: table;
}
div::after {
clear: both;
}
div {
*zoom: 1;
}
...which is a derivation of a fix I've been using for some time and was hoping to avoid. This succint version of the fix was found on this site.
So now every single div in the markup has got the clearfix hack applied to it whether it needs it or not. I'm yet to learn if this has any bad side-effects by being applied to all divs - I look forward to debugging and fixing when any problems surface ;-)
You provided nearly all possible solutions to this big layout question. I just want to point out my preferred solution.
Set font-size to the parent to 0 and resetting it again with REM's.
You'll have no trouble with your code and layout if there is no additional text inside the parent div (not the child divs).
REM's (Relative EM's) are not relative to the font-size of the parent elements (like normal EM's are), but relative to the root element of your document – the html element.
HTML:
<div class="parent">
<div class="child">column 1</div>
<div class="child">column 2</div>
<div class="child">column 3</div>
<div class="child">column 4</div>
</div>
CSS:
html {
font-size: 1em;
}
.parent {
font-size: 0;
}
.child {
display: inline-block;
font-size: 16px; /* Add pixel-based font-size to support IE8 and below */
font-size: 1rem; /* Don't use rem along with the font-shorthand to avoid problems in IE9/10 - see note below */
width: 25%;
}
No Browser support:
IE8 and below: Add pixel-based font-size to make it work.
IE9/10: not working with font-shorthand; use font-size instead!
(Opera Mini & iOS 3.2)
is there a ... way of preventing HTML whitespace from being rendered in the browser whilst using display:inline-block?
Yes, there are several ways. None of them really meet your criteria of 'hack-free' and 'tidy', but they do work.
Reformat ('minify') your code so that it doesn't have any white space between the elements.
This is probably the most hack-free and cross-browser solution. It isn't necessarily tidy though, and it means you're fixing your layout by adjusting the HTML rather than the CSS, which isn't ideal. But it does work well. If you want to keep your code readable, you could use HTML comments so you can keep the gaps but without them being in the DOM:
<div>block 1</div><!--
--><div>block 2</div><!--
--><div>block 3</div>
Still not ideal, but more readable than a massive single line of code.
Set the font-size to zero for the container, and back to full size again for the blocks.
This works really well. It's a pure CSS solution and easy to do. The down side is that it can be difficult to work with if you've got relative font sizes (ie setting back to 14px is fine, but setting to 1em won't work because 1em of the previous font size of zero is still zero).
Set a 1em negative margin to close the gap.
This also works pretty well, but can be imprecise.
Or is there an alternative to inline-block that can be used that has no unpleasant side effects?
There's always float:left. But that's got a whole range of different issues of its own. If you're using inline-block, the odds are good it's because you don't want to use floats.
Use position:absolute and do the layout manually.
You can use the float method you described in your question, but you didn't clear your floats, which is why the container collapses.
A good method is to use an ::after pseudo element attache to the container element to "auto-clear" itself:
div:after {
content: "";
display: table;
clear: both;
}
http://jsfiddle.net/s2rJW/3/
When i saw your "workaround" i was thinking: Why don't you use a <table>?
And then i figured this out:
div {
background: #ccc;
display: table;
width: 100%;
}
div div {
background: #eee;
display: table-cell;
width: 25%
}
<div>
<div>A column</div>
<div>A column</div>
<div>A column</div>
<div>A column</div>
</div>
It's hard to explain what I mean, so see this jsfiddle first: http://jsfiddle.net/Gsggy/
When a user clicks 1, div number 1 shows, same for the others, simple enough.
However, before a user has clicked on a number, there is no div there, because it relies on the # value in the URL
How can I set a default div that is there with a blank url e.g. www.jsfiddle.com but disappears when someone clicks a number and makes it www.jsfiddle.com/#1
The thing is you can't really target an element in a way to tell it "do something while someone else is the target".
There are however some workarounds to this dilemma. One solution would be to always dispay the default content and display the target elements above.
You can use the fact that elements that appear later in the dom are usually rendered above nodes which appear earlier. So you could have for example a negative top margin or an absolute positioned element cover up your default content.
Improving on your html structure:
<div class="default" id="z">0</div>
<div id="a">1</div>
<div id="b">2</div>
<div id="c">3</div>
This css does work:
.default {
display: block;
background: #eff;
}
div + div {
margin-top: -102px;
}
div:target {
background: #eef;
display: block;
position: relative;
}
The downside to this particular approach is that you need to know the exact dimensions of your default content.
See this fiddle: http://jsfiddle.net/Gsggy/4/
use nth-of-type or last-of-type selector and make a default div in last i think it will work in your case
I saw a similar question here, and did not see an answer. I'm having an issue where an element is floated right, inside a parent div, and it's causing the div to stretch the entire width of the page in IE7. This does not happen in any other browsers (Firefox and Chrome). I've also posted pictures after the question, for reference. The HTML I'm using is below:
<div id="journal" class="journalIE">
<div class="title_bar">
<div>
Testing
</div>
<div class="actions"></div>
<div class="clear"></div>
</div>
</div>
The CSS I'm using for these tags is below as well. One thing I noticed consistent between the other person's question referenced above, and my issue, is that both parent div's have positioning applied (person above has absolute, I have fixed).
#journal
{
z-index: 1;
}
.journalIE
{
right: 1px;
bottom: 18px;
position: fixed;
}
#journal .title_bar
{
background: #F3F3F3;
border: 1px solid #C5D6E8;
color: #363638;
font-size: 11pt;
font-weight: bold;
height: 20px;
padding: 4px;
margin-bottom: 4px;
}
#journal .title_bar .actions
{
float: right;
}
.clear
{
clear: both;
}
Notice that the 'actions' class is floated right. If I take away that float, my box looks like this. But with the float added, it stretches the entire screen, and looks like this. Is this a known IE bug, because it's not happening in any other browser, and it's driving me crazy.
For those wondering, I did have content in the 'actions' div, but have stripped away everything down to the root problem.
Any assistance would be greatly appreciated. Thanks very much.
You need a width: *A floated box must have an explicit width (assigned via the 'width' property, or its intrinsic width in the case of replaced elements). *
via: W3C
Do this
<div id="journal" class="journalIE">
<div class="title_bar">
<div class="Test">
Testing
</div>
<div class="actions"></div>
<div class="clear"></div>
</div>
and then add a Css class
.Test
{
float:right;
}
should do it, let us know if it does not work.
MNK
I'm not entirely sure what you want, as you didn't explain what you wanted to do with the "actions" div, but if you wanted the "actions" div to float right next to the "Testing" div, I just tried making a separate .floatr class, or it will also work if you just apply style directly to div.
.floatr {
float: right;
}
with .floatr class, apply that to "actions" div:
<div class="actions floatr"></div>
I don't know why, but it seems to me that "actions" div is ignoring the float setting in the class you set in that manner. I personally prefer to apply multiple classes to divs, which allows me to reuse that class over other divs for which I want that effect, but I've heard that some browsers will ignore any classes declared after the first one. Oh well, I haven't run into that problem yet with major browsers...
Oh wait.
I looked over code again, and I think you just had a problem with how you set your classes. Your "actions" div was missing out on the action, try adding a comma to CSS:
#journal .title_bar, .actions
{
float: right;
}
I guess sometimes to figure something out you gotta apply effect directly to make sure it can behave in the manner you expect it to, and then probably figure it's some sorta syntax error if it does work. heh.
How do you overlap an element over another element that is positioned relatively in Internet Explorer? Z-index doesn't work, it always appears behind the relatively positioned element.
Looks like I'm kidding, but I am not
.myLinkCssClass {
background : url(#);
}
You're not by any chance trying to put something over a combobox (select tag), iframe or flash movie right?
In those cases z-index is a lost cause.
Otherwise what browser version are you using and are you using absolute positioning?
I had a real pain with this problem that this particular workaround wasn't relevant for. It's a little hard to explain so I'll try using code:
<div id="first" style="z-index: 2">In between</div>
<div id="second" style="z-index: 1">In the back
<div id="third" style="z-index: 3">Foreground</div></div>
The problem is that setting the parent's z-index to a higher value would move it to the foreground instead of the back where its supposed to be. I stumbled upon a solution completely by accident: I made a copy of the foreground element (id=third) outside its parent.
<div id="first" style="z-index: 2">In between</div>
<div id="third" style="z-index: 3; visibility:hidden">Foreground</div>
<div id="second" style="z-index: 1">In the back
<div id="third" style="z-index: 3">Foreground</div></div>
Its worth mentioning that in my original code the elements don't have IDs so I don't suffer from 2 elements sharing the same one and invalidating my HTML.
I think its safe to classify this weirdness as another bug that happens to help with the original, but it works, at least for me. Hope somebody finds this useful!
Create and then set an additional transparent background image on the element you want to have on top. For me it finally worked in IE8. SASS:
#galerie-link {
position: absolute;
z-index: 1000;
top: 25px;
left: 40px;
a {
display: block;
width: 185px;
height: 90px;
background-image: url(../images/transparent.png);
}
}
I wanted to note that if you are using IE8 and below, it does not support CSS3 filters. This was my issue.
I was using:
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#black00', endColorstr='#black00', GradientType=0);
No matter what I set my position or z-index to, you could not see the other layer because it was causing a complete mask over that layer (instead of going from clear to black and to clear again).
By removing the CSS3 filter for just IE8, I was able to solve my problem.
Hope this helps someone who runs into the same issue.
I had the same problem in an html where many repeated relative positioned divs were blocking absolute positioned div's view. The workaround provided by www.brenelz.com, that I've already used with success wasn't working in this case. So, the following worked for me:
I removed the relative positioning from those divs I've mentioned first, then added a CSS to turn those divs on relative when hover. Let me show you the code:
Before:
DivThatYouMustHover {
height: 300px;
position: relative;
width: 200px;
}
After:
DivThatYouMustHover {
height: 300px;
width: 200px;
}
DivThatYouMustHover:hover {
position:relative;
}
This way the others 'sisters' of that div stay with normal positioning and don't interfere with the layout.
It worked very well for me! I hope it helps you too.
Evening All,
Had a question on whether or not the use of Absolute postioning in my context would be considered wrong by the CSS gods. Basically what I am doing is using it to position images for the header bar of my website.
We can use SO as a good example. So the main logo at the top of our page is StackOverFlow followed by a menu. On the right side we have Ask Question. Now pretend with me that both of those elements are pictures. Would it be considered within reason to absolutely position those so that we don't have to fight with any other CSS div positioning?
Cheers,
Mike
In my experience, you will generally find yourself disappointed with absolute positioning over, say, floats, meaning you'll find some nasty corner cases that will make the whole exercise a hair-pulling experience.
The one exception to that is relative+absolute positioning. When used properly that can be incredibly useful.
But to do a heading like on the SO site I would probably just use floats.
<div id="header">
<img id="left" src="image1.png">
<img id="right" src="image2.png">
</div>
with:
#header { overflow: hidden; }
#left { float: left; }
#right { float: right; }
Most of the time, that's problem solved.
It may be that only one of these needs to be floated. If its the one on the left:
<div id="header">
<img id="left" src="image1.png">
<div id="right">Some more content</div>
</div>
with:
#header { overflow: hidden; }
#left { float: left; width: 150px; }
#right { margin-left: 150px; }
I am guessing you will only need to absolutely position one of the two items you discuss. Leave the logo in normal page flow, and position the other item.
You could also use float:right on the one item, but that can be hard to troubleshoot across the spectrum of browsers.
I am not in touch with the CSS gods, but I say your plan of attack sounds like a fine use of absolute positioning.
Just be sure whatever wraps the two elements has position: relative
Absolute positioning can be really helpful when both elements are a different height
i would say probably easiest to make the right side image/div a float:right
that will let you shift things around fluidly