Limit text to the width of sibling image / auto width in CSS - css

I am essentially trying to create a version of the "figure" element (upcoming in HTML5), whereby I have an image with a short description below it.
However, I want to limit the width of this entire element to that of the image, so the text isn't wider than the image (wrapping to multiple lines if necessary).
Basic HTML:
<div class="figure">
<img src="..." alt="..." width="..." height="..." /><br />
A description for the image
</div>
I'm well-versed with CSS but I can't think of any pure CSS solution, without adding a style="width:100px" to the div to match the image width.
Update: After a bit of searching and thinking, the best method seems to be using an inline width on the div. I will keep the width attribute on the image, in case I wish the div to be a bit wider than the image (for example to accomodate a longer caption).
This approach also means I could have two images side-by-side with a caption below. If I have a set of images the same size, I can of course add an extra style to each div.
Thanks to everyone who answered!

This could also be accomplished using 'display: table-caption' for the caption, as follows:
HTML
<div class="wrapper">
<img src="image.jpg" />
<div class="caption">My caption...</div>
</div>
Stylesheet
.wrapper {
display: table;
}
.caption {
display: table-caption;
caption-side: bottom;
}
This block can also be floated left of right of other text. I've tested this in IE8+. Here's a JSBin example: http://jsbin.com/xiyevovelixu/1

For setting the width to match the image automatically you could use
.figure {
display: table;
width: 1px;
}
This makes the div behave like a table (not supported in Internet Explorer). Or you could use a table instead of the div. I don't think there is another way of setting the width automatically.
Edit: The simplest way is to forget about the auto width and set it by hand. If it is really needed you can use JavaScript or a table. In this case the use of a table is not so ugly because you are addressing a limitation of the HTML version. In the case of server-side scripting you could also set the width when generating the page.

Stylesheet
div.figure img,
div.figure div.caption {
width: 100%;
}
div.figure div {
overflow: hidden;
white-space: nowrap;
}
note: to enable wrapping just remove that last css line
HTML
<div class="figure" style="width:150px;">
<img src="logo.png" alt="logo" />
<div class="caption">A description for the image</div>
</div>
I've checked it in Chrome, Firefox and IE7 and it looks good in all three. I realise this has the width on the div and not the img, but at least you only need to set the width in one place. Short of using css-expressions (IE only) I can't see a way of setting the outer divs width to the width of the first child element.

I had the same problem and after reading this decided to use an inline-style on the surrounding element. Seems the better solution over using a table to me.

You can also acheive this using the following solution proposed by Temani Afif in his blog post (All credits to him, I just don't want the solution to be forgotten)
<div class="box">
<img>
<h1>Lorem ipsum dolor ..</h1>
</div>
.box {
display: inline-block;
}
h1 {
width: 0;
min-width: 100%;
}
Make the container inline-block, and makes the h1 (or whatever text tag you use) occupy the space dictated by the sibling element. It's essentially a hack, but it works! No unintended semantic consequences like the table solutions

You could use the display:table solution for all other browsers, and a CSS Behaviour for Internet Explorer.

Related

Responsive divs width and height with css

I am trying to build a horizontal scrolling layout, composed of image blocks:
<div class="container">
<div class="item">
<img src="http://placehold.it/200x300">
</div>
<div class="item">
<img src="http://placehold.it/400x300">
</div>
<div class="item">
<img src="http://placehold.it/300x300">
</div>
</div>
I used display:inline-block and white-space: nowrap; properties to achieve this, and it does work but browsers don't seem to recompute block widths on resize?
Check here: https://jsfiddle.net/g597w3Lr/2/ and try resizing the browser..
Here is a screen grab to better understand what is my problem:
https://youtu.be/VxKo4gysc1o
At first all images are well positioned and i can scroll horizontally: perfect.
I then resize the browser
images are resizing, not the .item wrappers. White gaps appear :(
Basically i was expecting same feature as with vertical scrolling, i.e. adapting width depending on content size.
I actually dont even understand the logic here..
Is there any way to get over this?
Thanks!
Original answer
EDIT 2: Looking at your video I think the new approach is what you are looking for.
You have to display your divs with .item class as inline and remove your white-space: normal property.
.item {
display: inline;
height:100%;
}
Updated JSFiddle.
Explanation:
I am not an expert of CSS so if someone see some mistake please correct me.
When you display an element as inline-block as the official documentation says:
inline-block
Causes an element to generate an inline-level block container. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.
which means that the element that you display as inline-block acts like a block but you can set it inline (in the same line). This means that you can set a div (which is display: block as default) in a single line. You can also see it here:
The div element, short for division, is the block level generic container.
Also, inline elements cannot get height/width properties so this is the reason why when you display your divs with .item class as inline, they wrap the content but not get the height/width that they should correspond to take (from their parents in your case, as you put them with %).
If you display them as inline-block it does not changes anything about their default height/width properties. Just allows you to display them in a single line.
JSFiddle to see the three divs (inline/ inline-block / block, as default).
You will have to modify slightly your css
HTML
<div class="container">
<div class="item">
<img src="http://placehold.it/200x300">
</div>
<div class="item">
<img src="http://placehold.it/400x300">
</div>
<div class="item">
<img src="http://placehold.it/300x300">
</div>
</div>
CSS
html,body {
height:auto;
}
.container {
display: inline-block;
white-space: nowrap;
height:auto;
}
.item {
display: inline-block;
white-space: normal;
}
.item img {
width:100%;
height:100%;
}
Fiddle
check it see that's what you want ?
I manage your classes with border:solid 1px red;
and use width:100% in some classes.
also in class item:
width:100%;
https://jsfiddle.net/g597w3Lr/6/

Center multiple images horizontally in CSS

I know this question is very popular, but I couldn't find any elegant answer.
I need to align horizontally 2 images and center them. I've already read about inline-block and I pretty good at margins (margin 0 auto trick), paddings and other geometrics. The thing is... that my html code is parsed from markdown by javascript parser (not mine and complex) and each element enclosed into <p> tag. But my text-align for <p> tag is justified.
I understand that answer on my question is to use <div> right in markdown around images and set its text-align to center, but I seek for more elegant way to do it because I prefer clean and modern coding with html5 semantics and look into the future where <div> elements would be no more.
Basically, my question is simple: is it possible at all to do such a thing without outside block?
UPD: jsfiddle - http://jsfiddle.net/8274L7wc/
It'd be perfect if I could change style of <p> based on child element <img>, but as far as I know - this is impossible by css.
Also I suppose I could use CSS calc() method to calculate width and set precise margins, but I think even div would be better than this.
I can't use text-align:center on <p> element because it would make everything centered, not only images.
UPD2:
I've made quick temporary solution by using jquery .parents method to set all <p> which contain <img> tag - centered:
$('img').parents('p').css('text-align', 'center');
Here are a couple of answers that you might find useful.
FIRST
There is a general rule in web development that says you should always try to use basic browsers' functions before relying on CSS. This is part of what we call progressive enhancement. Following this rule, the best way to solve your problem is by adding the html5 element <figure></figure>. Here is the doc and below is an example using your jsfiddle:
p {
text-align: justify;
}
figure { /* Then you can center your img inside the figure element */
text-align: center;
}
img { /* You don't need margin 0 auto or display block, let the browser do its work */
width: 6.25em;
height: 6.25em;
}
<p>
<figure> <!-- You can add several img in a figure element -->
<img src="https://dl.dropboxusercontent.com/u/70091792/Pages/2/workspace2.png" alt="First workspace" title="" />
<img src="https://dl.dropboxusercontent.com/u/70091792/Pages/2/workspace2.png" alt="Web-browser on the second workspace" title="" />
</figure>
</p>
SECOND
If you don't want to add an element to your HTML markup then CSS can only help you if you now how many images you will have and what will be their size. In this case you can calculate with calc() the dimensions needed and add a padding-left on first image. As you can see this is quite complicated, hard to maintain and definitely not considered as best practices. Here is an example:
p {
text-align: justify;
}
img {
width: 100px;
height: 100px;
}
p img:first-child {
margin-left: calc(50% - 100px)
}
<p>
<img src="https://dl.dropboxusercontent.com/u/70091792/Pages/2/workspace2.png" alt="First workspace" title="" />
<img src="https://dl.dropboxusercontent.com/u/70091792/Pages/2/workspace2.png" alt="Web-browser on the second workspace" title="" />
</p>
Good luck!
<p>
<img src="http://leone.ge/mem/img/image2.png" />
<img src="http://leone.ge/mem/img/image2.png" />
</p>
----
p{
display:block;
width:100%;
background:tan;
text-align:center
}
p img{
display:inline-block
}
view result here: http://jsfiddle.net/kr76uu46/2/
Here there are 7 css ways to center horizontally and vertically an element in the middle of a div (or a body). Than you can create a second div and you get your solution.
text-align:center
margin:auto
display:table-cell
position:absolute
translate function
flexbox
calc function
img{
width: 100%;
max-width: 150px; //your width
height: auto;
position: relative;
left: calc(25%);
}
<img id="b" src="http://placehold.it/150x150" alt="Sample Image 6">
<img id="a" src="http://placehold.it/150x150" alt="Sample Image 6">
Otherwise, if you are still interesting looking for different ways (css-based solution) check this LINK

Inline-Block without margins?

I have several DIV's displayed as inline-blocks; and they seem to be getting spacing automatically applied in between them from the browser. They have margin/padding set to 0. Is there a way to correct this without using negative margins?
Sam, that space you're seeing is actually whitespace. That's why removing the paddings and margins does nothing. Let me explain. When you have this:
HTML
<div>
a
a
a
a
</div>
this is how it's rendered:
a a a a
...right?
So, if you have this:
<div>
<div style="display:inline-block"></div>
<div style="display:inline-block"></div>
<div style="display:inline-block"></div>
</div>
...you'll get the same thing:
block [space] block [space] block
Now... there are many different solutions to this problem. I believe the most common is commenting out the whitespace in the html:
<div>
<div style="display:inline-block"></div><!--
--><div style="display:inline-block"></div><!--
--><div style="display:inline-block"></div>
</div>
I don't like it though - I prefer keeping the html as clean as possible. My preferred way is to set the parent's font-size to 0, and then set back the desired font-size on the inline-blocks themselves. Like so:
div {
font-size: 0; /* removes the whitespace */
}
div div {
display: inline-block;
font-size: 14px;
}
You don't need to use negative margins to offset the original margins.
Instead you can override them with the following:
* { margin:0; }
or:
.div { margin:0; }
if it's element specific.
EDIT:
It appears the problem may be a result of unintended whitespace. For instance:
<div style="display:inline-block">
...
</div>
<div style="display:inline-block">
...
</div>
There exists white space between the two dividers and the browser will print the white space as a result. To fix this, you'll need to change it to:
<div style="display:inline-block">
...
</div><div style="display:inline-block">
...
</div>
Enjoy and good luck!
You can use both display: inline-block and float: left to remove that space.
Here goes plunkr: https://plnkr.co/edit/Sn3NG77asiXO8UrrpxWD?p=preview
Inline-block is originally a IE6 hack
This is what its used for:
To fix the IE6 double-margin bug on floated elements
To place multiple block-like elements on the same horizontal line
without floating them(if you can't float 'exceptional cases)
To allow an inline element to have width and/or height while still
remaining inline
To allow an inline element to have padding or margins
So if you wanna have multiple divs beside eachother please use float, its gonna solve many of your css problems that inline-block can cause, especially cross browser issues
More about inline-block here arcticle 9.2.4
Best regards
SP
please comment if disagree
Another way I have found the method altering the word-spacing on the parent container works for me https://jsfiddle.net/1ex5gpo3/2/
.parent {
word-spacing: -1em;
}
.child {
word-spacing: normal;
display: inline-block;
}

Centering 2 divs of unknown width in IE6 and IE7

OK so what would happen if I have 2 divs (one containing text, the other an image). The image always has a static width but the text varies. hence making its containing div variable.
I can make it work for all other browsers (except IE6 and IE7) by using CSS display:table. IE6 and 7 don't have that so I can't find a workable solution to center them all.
... so you know what I'm talking about...
.container{text-align:center; width:100%}
.container .centered{display:table; margin:0 auto}
<div class="container">
<div class="centered">
<div id="text">varying length text</div>
<div id="image">IMAGE</div>
</div>
</div>
Quite apart from the lack of IE support, setting display: table as you have without its children using display: table-row/table-cell results in undefined behaviour. It doesn't make sense to put block elements directly inside a table element and the browser might do anything at all.
What you are trying to do is get shrink-to-fit width behaviour without using float, which is a normal way of getting shrink-width but requires that the block in question goes to the left or right not centre. Probably a better way of saying that would be to use an inline-block:
.centered { text-align: center; }
.centered span { display: inline-block; border: dotted red 1px; }
<div class="centered">
<span id="text">varying length text</span>
</div>
<div class="centered">
<span id="image">IMAGE</span>
</div>
(You have to use a naturally-inline element like span to make it work under IE<8; div would fail. There is also -moz-inline-box if you need to target Firefox 2.)
Are you using quirksmode or standards compliant mode? In other words have you included a DOCTYPE declaration at the top of your html page?
You shouldn't need to use display:table just margin:auto should do the trick provided you are using a standards mode.

CSS layout, use CSS to reorder DIVs [duplicate]

This question already has answers here:
How can I reorder my divs using only CSS?
(27 answers)
Closed 6 years ago.
Given that the HTML
<div>
<div id="content1"> content 1</div>
<div id="content2"> content 2</div>
<div id="content3"> content 3</div>
</div>
render as
content 1
content 2
content 3
My question:
Is there a way to render it as below by using CSS only without changing the HTML part.
content 1
content 3
content 2
This can be done in browsers that support the CSS3 flexbox concept, particularly the property flexbox-order.
See here
However, support for this is only in current versions of most browsers still.
Edit Time moves on and the flexbox support improves..
This works for me:
http://tanalin.com/en/articles/css-block-order/
Example from this page:
HTML
<div id="example">
<div id="block-1">First</div>
<div id="block-2">Second</div>
<div id="block-3">Third</div>
</div>
CSS
#example {display: table; width: 100%; }
#block-1 {display: table-footer-group; } /* Will be displayed at the bottom of the pseudo-table */
#block-2 {display: table-row-group; } /* Will be displayed in the middle */
#block-3 {display: table-header-group; } /* Will be displayed at the top */
As stated there, this should work in most browsers. Check link for more info.
It might not exactly match what you're after, but take a look at this question:
CSS positioning div above another div when not in that order in the HTML
Basically, you'd have to use Javascript for it to be reliable in any way.
This is one of the classic use-cases for absolute positioning--to change rendering from source order. You need to know the dimensions of the divs to be able to do this reliably however, and if you don't javascript is your only recourse.
I was messing around in Firefox 3 with Firebug, and came up with the following:
<div>
<div id="content_1" style="height: 40px; width: 40px; background-color: rgb(255, 0, 0); margin-bottom: 40px;">1</div>
<div id="content_2" style="width: 40px; height: 40px; background-color: rgb(0, 255, 0); float: left;">2</div>
<div id="content_3" style="width: 40px; height: 40px; background-color: rgb(0, 0, 255); margin-top: -40px;">3</div>
</div>
It's not perfect, since you need to know the heights of each container, and apply that height value to the negative top margin of the last element, and the bottom margin of the first element.
Hope it helps, nd
I got it to work by doing this:
#content2 { position:relative;top:15px; }
#content3 { position:relative; top:-17px; }
but keep in mind that this will not work for you as soon as you have dynamic content. The reason I posted this example is that without knowing more specific things about your content I cannot give a better answer. However this approach ought to point you in the right direction as to using relative positioning.
One word answer: nope. Look into XSLT (XML Stylesheet Language Transforms), which is a language specifically geared towards manipulating XML.
If you know the height of each element then it is a simple case of vertical relative positioning to swap around the orders. If you don't know the heights then you either have to give them heights and allow the divs to get scroll bars if there is any overflow or calculate it all with JavaScript and add the relative positioning on-the-fly.
with jquery you can simply do:
$('#content2').insertAfter($('#content3'));
I don't think there's a way to do it with CSS, except to force fixed positioning of each of the divs and stack them that way.

Resources