Let's say you want to replace an anchor with an image, and you make that image the anchor's background. You still want the text wrapped by the anchor to be there for accessibility reasons, but you don't want it visible. A well known technique is to use something like text-indent: -9999px; along with overflow: hidden;
So let's say our anchor box is 50px x 50px, why wouldn't we just do text-indent: 50px? This would shove the text into the hidden overflow of the anchor, no matter how long it gets!
Well, let's just look at what happens when you do that
http://jsfiddle.net/C29Ma/
<div class="image">Hide me please</div>
div.image {
width: 50px;
height: 50px;
background: url(http://placehold.it/50x50) no-repeat;
text-indent: 50px;
}
Because the text is longer than 50px wide, it wraps around. Only the very first line is indented by 50px.
The negative indent technique came about before there was widespread support for pseudo elements or controlling word-wrapping. It does the job well enough, so people don't change how they do things when a newer/better way comes along.
Your suggestion is very close to one of the modern techniques, though
http://www.zeldman.com/2012/03/01/replacing-the-9999px-hack-new-image-replacement/
.hide-text {
text-indent: 100%;
white-space: nowrap;
overflow: hidden;
}
Related
I observe that text-align: center, while creating equal space around the left and right of the text from its container block element's boundaries (div in this case), also changes the alignment of the text to center. In this, it violates the Single Responsibility Principal.
With text-align: center
div {
box-sizing: border-box;
width: 600px;
height: 500px;
border: 4px solid red;
padding: 0 150px 0 150px;
display: table-cell;
vertical-align: middle;
text-align: center;
}
<div>This is a long piece of text that runs into many lines of reading. Some people like to sleep, and some like to drink water. This is looking like a poem. It is even aligned like one. What a pity!</div>
A few things to note for the casual reader:
I am not asking how to vertically align text.
I know I can do what I want if I took a div within a div. I am not asking for alternate solutions to a problem I am trying to solve. I am asking if there is a way to do it without resorting to a kludge such as taking a containing div.
With a kludge: taking a div inside a div
body > div {
box-sizing: border-box;
width: 600px;
height: 500px;
border: 4px solid red;
display: table-cell;
vertical-align: middle;
padding: 0 150px 0 150px;
}
div > div {
text-align: justify;
margin: 0 auto;
}
<div>
<div>This is a long piece of text that runs into many lines of reading. Some people like to sleep, and some like to drink water. This is NOT looking like a poem. Oh, so nice! But it uses a hack, what the fack!</div>
<div>
I was wondering if there was a way to horizontally center text within a containing block such as a div while retaining the text alignment to left or justify.
No, there isn't and for a good reason. For if there were to be one such inbuilt solution within the CSS engine itself, without you setting the padding, who would decide how wide the text content must be?
Your best bet is to do what you were already doing. That is, to set the padding on the left and right sides, and to leave text-align: justify (or left as you please). That would do exactly what you wanted.
The problem with the approach that you are thinking of is that you somehow need to define how wide the centered text should be. In you're example you were setting the padding and the width and by that implicitly setting the width that was left for the text in the middle.
The only real solution to making sure that something only takes a predefined with in a container is actually creating a DOM-element for it. This means that you probably can't avoid the extra div here if you do not want to use the padding/width hack.
I am trying to understand the rules behind z-index and how it interacts with the overflow property.
I have this html:
<body>
<div class="cell">
Here is some text to keep things interesting
<div class="boxy"></div>
</div>
</body>
And this css:
.boxy {
position: absolute;
z-index: 9999;
top:70px;
width: 50px;
height: 50px;
background: #0FF;
}
.cell {
border: 2px solid #F00;
position: relative;
/* comment these two lines out and the box appears */
/* or change them both to 'visible' */
/* changing only one of them to 'visible' does not work */
overflow-y: auto;
overflow-x: auto;
}
I would have expected that the cyan box appears even though it is out of the size of the div.cell because its z-index and its position are set.
However, the only way to make the cyan box appear is to comment out the overflow-x and -y lines.
My question is: How can I make the cyan box appear on the screen while keeping the overflow as either hidden or auto? But more importantly, I'm looking to understand why this is happening. What are the css and layout rules being applied here?
See my Plunkr. This example, is of course a much simplified version of the HTML/CSS I am actually working with.
EDIT
There seems to be some confusion in the answers below because I didn't explain things well enough. If you comment the two overflow lines out, you can see that the cyan box appears. It appears outside of the border of .cell. Why does this happen? How can I make the cyan box appear, while still hiding overflow and z-index?
The reason the cyan box appears only when overflow-x and overflow-y are visible, and disappears otherwise, is simply because the cyan box is overflowing the cell box. overflow: visible simply means "paint this box even if it is overflowing its containing block" — the cell box is the containing block of the cyan box because its position is relative. Any other values of overflow cause overflowing content to be clipped from view. There is nothing special going on here; in particular, the z-index is completely irrelevant and there is no such interaction as the question title alludes to (and there really is no reason to set it to such a huge number unless you're worried about scripts injecting other elements into the cell).
The only way to allow the cyan box to appear while the cell has a non-visible overflow is to remove position: relative from the cell and apply that declaration to the parent of the cell (in your example, it's the body). Like this:
body {
position: relative;
}
.boxy {
position: absolute;
z-index: 9999;
top: 70px;
width: 50px;
height: 50px;
background: #0FF;
}
.cell {
border: 2px solid #F00;
overflow: auto;
}
<div class="cell">
Here is some text to keep things interesting
<div class="boxy"></div>
</div>
Absolute-positioned elements do not contribute to the dimensions of their parents.
Therefore, the .cell DIV has no content that affects its dimensions, making it 100% wide by 0px high.
To make the element appear, you'll have to add a height to .cell that will encompass the DIV, in this case 120px (70px top + 50px height).
The Parent Class cell need to be set it's height. because height of absolute element doesn't affect it;s parent.
.boxy {
position: absolute;
z-index: 9999;
top:70px;
width: 50px;
height: 50px;
background: #0FF;
}
.cell {
border: 2px solid #F00;
position: relative;
/* comment these two lines out and the box appears */
/* or change them both to 'visible' */
/* changing only one of them to 'visible' does not work */
overflow-y: auto;
overflow-x: auto;
min-height: 120px; /* height 70px(Top)+50px*/
}
Your problem
Your problem is related to cell node that hides boxy when overflow is specified on cell node.
The reason
The reason behind is that boxy with position absolute does not contribute to height of cell and overflow hides it.
Why is it shown without overflow?
By default overflow is visible, which for browser means do not do anything special for overflow functionality and it does not need to render overflow => does not hide boxy.
Z-indices are local inside their clipping hierarchical parent context. This is very non-intuitive. They have their own z-stack context, which normally parallels that of the enclosure hierarchy. But they're still subject to clipping! Which can be a real pain if you're intuitively expecting the z-indices to be absolute.
Note that some jquery containers, such as accordion, quietly specify overflow: auto. Even if it's not explicitly in your code. (This can be overridden locally after it's found.)
Also note that if overflow-x: visible is set, but overflow-y is set to a non-visible, then the rendering engine quietly internally changes overflow-x to be the same as overflow-y for your amusement. But you found this out already.
You probably should be able to circumvent the unwanted non-"visible" overflow clipping, even with your high z-index, by invoking transform: translate(0,0); [or whatever desired offset, % or pixels] inside the style of the div that you want to levitate. Transform should create a new local z-stack for that element and its children. Which will let you get around an overly-restrictive parent or grandparent.
So, I've managed to make this CSS work, but I'm not 100% sure why it does. I know that's the classic programmer's scenario. I'd like to know why it does, though, so that I can get better.
Here are the two JSfiddle cases (they're exactly the same but with one line different):
With display:block
With float:left
As you can see, the important line of CSS:
.name::before {
content: '';
background: purple;
position: relative;
float: left; /* OR -display: block;- */
height: 22px; width: 100%;
margin-top: -22px; margin-left: -11px;
padding: 0 0px 0 22px;
}
With display:block, the pseudo-element matches the width of the main element (including the borders and padding. However, with float:left, the pseudo-element actually extends the width of the main element; if you change the padding-left to 11px, the increased width disappears, but the ::before stops short and doesn't include the main element's padding+border. This makes me think that inline elements affect other elements that it doesn't share a line with, as long as they're in the same container. Is that right?
Oddly, if you make change the padding to padding: 0 11px, it doesn't extend the right side of the ::before to the edge of the main element like I thought it would. Why is that?
Thanks!
My opinion is:
display: block;
only display the element in block,
while
float: left;
does push the element to the very left of its parents.
If you want to have all the elements to be in one line,
try to use display: inline;
I am beginning to dabble in responsive design, and as a result am trying to pinpoint best practices in my CSS. I am working on placing caption text over what will eventually be a custom, jquery driven image slider.
All of this is running at http://www.taylorp0994.net/websites/cincoschool/index.html, so please look to the live results and code for further information.
I have achieved what appears to be a workable solution; however, I fear it is not semantic to use pixels, regardless of context. How can I use percentages to achieve the same look and what approach should I take, (margin-top, position:relative/top, etc.)? I've yet to have much success with any of the obvious except for my current solution which is to position:relative the caption box and move it up via top:-46.5px.
The work you've posted looks really promising!
Two things worth mentioning from my cursory look:
There's nothing particularly 'wrong' with using pixel measurements. The only time this will potentially become a problem for you is with the caption's length. If the text is likely to change length (and thus: roll onto two lines), then using a set height adjustment won't work.
There's a lot of empty 'p' tags within the caption, is that deliberate?
The way I tend to tackle this type of task is to use positioning:
Have a single div wrap that contains both the image and the caption. Position this relative;
Set the image z-index to a low number;
Set the caption's z-index higher, and set to position: absolute, bottom: 0. This will position the caption off the bottom edge of the parent div, which will in turn inherit it's height from the image.
Two secs and I'll post an example.
Here you go: http://jsfiddle.net/HhuhR/ This is very quick-and-dirty but should help put you on the right track:
<style>
.img-wrap{
width: 60%; /*just here for the preview */
position: relative;
}
.img-wrap img{
max-width: 100%;
z-index: 1
}
.img-wrap .caption{
display: block;
width: 100%;
position: absolute;
bottom: 5px; /*if using padding in the caption, match here */
left: 0;
z-index: 2;
margin: 0;
padding: 5px 0;
text-indent: 5px;
color: #fff;
font-weight: bold;
background: rgba(0, 0, 0, 0.4);
}
</style>
<div class="img-wrap">
<img src="http://taylorp0994.net/websites/cincoschool/img/slide1.png" alt= "">
<span class="caption">Lorem ipsum dolor sit amet</span>
</div>
Do remember that as your viewport width gets narrower, the caption text will dominate the image (as the image itself gets smaller). I tend to identify a point in my design where this becomes a problem and simply overwrite the caption position for bottom/left and set position: relative - this drops the caption directly beneath the image rather than over-lapping (and potentially fully covering) it.
What's the best way to align icons (left) and text (right) or the opposite text on left and icon on right?
Does the icon image and text have to be the same size? Ideally I would like them to be different but be on the same vertical alignment.
I am using background-position css property to get the icons from a larger image.
Here is how I do it now, but I am struggling with either getting them to be on the same line or be vertically aligned to the bottom.
Text
This is what I get after I try your suggestions.
Though the text is now aligned with the icon, it is superimposed over the icon to the right of the icon that I want. Please note that i am using the background position to show the icon from a larger set of images.
Basically I am getting
<icon><10px><text_and_unwanted_icon_to_the_right_under_it>
<span class="group3_drops_icon group3_l_icon" style="">50</span>
group3_drops_icon {
background-position:-50px -111px;
}
.group3_l_icon {
-moz-background-clip:border;
-moz-background-inline-policy:continuous;
-moz-background-origin:padding;
background:transparent url(/images/group3.png) no-repeat scroll left center;
height:35px;
overflow:hidden;
padding-left:55px;
}
I usually use background:
<style type="text/css">
.icon {
background-image: url(path/to/my/icon.jpg);
background-position: left center;
background-repeat: no-repeat;
padding-left: 16px; /* Or size of icon + spacing */
}
</style>
<span class="icon">Some text here</span>
You can do it on the same line using vertical-align and line-height
<p style='line-height: 30px'>
<img src='icon.gif' style='vertical-align: middle' />Icon Text
</p>
Alternatively, you can go the background approach with no-repeat and positioning:
span.icontext {
background: transparent url(icon.gif) no-repeat inherit left center;
padding-left: 10px /* at least the width of the icon */
}
<span class="icontext">
Icon Text
</span>
Sadly, neither of these answers are bullet proof and each have one big flaw.
#rossipedia
I used to implement all my icons this way and it works quite well. But, and this is a big but, it does not work with sprites, since you're using the background-position property to position the icon inside the container that includes your text.
And not using sprites where you can is bad for performance and SEO, making them imperative for any good modern website.
#Jamie Wong
The first solution has two markup flaws. Using elements semantically correctly is sadly underrated by some, but you'll see the benefits in prioritizing form in your search engine ranking. So first of all, you shouldn't use a p-tag when the content is not a paragraph. Use span instead. Secondly, the img-tag is meant for content only. In very specific cases, you might have to ignore this rule, but this isn't one of them.
My Solution:
I won't lie to you, I've checked in a lot of places in my time and IMHO there is no optimal solution. These two solutions are the ones that come closest to that, though:
Inline-Block Solution
HTML:
<div class="container">
<div class="icon"></div>
<span class="content">Hello</span>
</div>
CSS:
.container {
margin-top: 50px;
}
.container .icon {
height: 30px;
width: 30px;
background: #000;
display: inline-block;
vertical-align: middle;
}
.container .content {
display: inline-block;
vertical-align: middle;
}
"display:inline-block;" is a beautiful thing. You can do so much with it and it plays very nicely with responsive design.
But it depends on your client. Inline-Block does not work well with IE6, IE7 and still causes problems with IE8. I personally no longer support IE6 and 7, but IE8 is still out there. If your client really needs his website to be usable in IE8, inline-block is sadly no option. Assess this first. Replace the black background of the icon-element with your sprite, position it, throw no-repeat in there and voilà, there you have it.
Oh yeah, and as a plus, you can align the text any way you want with vertical-align.
P.S.: I am aware that there's an empty HTML-tag in there, if anyone has a suggestion as to how to fill it, I'd be thankful.
Fixed Height Solution
.clearfix:after {
content: ".";
display: block;
clear: both;
visibility: hidden;
line-height: 0;
height: 0;
}
.clearfix {
display: inline-block;
}
html[xmlns] .clearfix {
display: block;
}
* html .clearfix {
height: 1%;
}
.container {
margin-top: 50px;
border: 1px solid #000;
}
.container .icon {
height: 30px;
width: 30px;
background: #000;
float:left;
}
.container .content {
line-height: 30px;
float: left;
display: block;
}
I hate this one. It uses a fixed line height for the text, and if you choose the same height as the Icon's box, the text is centered to that height. To align the text to the top, cut the line height, and as to the bottom, you'll have to fix that with position: absolute and a fixed width and height for the container. I'm not going to get into that unless someone requests it, because it's a whole issue for itself, and brings with it a lot of disadvantages.
The main disadvantage of this path is the fixed height. Fixed heights are always unflexible and especially with text, it can cause a bunch of problems (You can no longer scale the text as a user without it being cut off, plus different browsers render text differently). So be sure that in no browser the text is cut off and that it has some wiggle room inside its line height.
P.S.: Don't forget the clearfix for the container. And, of course, replace the black background with your sprite and according position + no-repeat.
Conclusion
Use inline-block if at all possible. ;) If it's not, breath deeply and try the second solution.