9

I can simply use float to achieve the text wrap around <img> element and I understand that <img> is an inline element and <p> is a block level element so to make them inline, I should either make <p> an inline element or use <span> instead.

The thing is that if I treat them all as inline elements, it leaves a huge white space next to the image and on top of the text.

enter image description here

I would like to know what causes the blank space.

Here is my JS Fiddle

Seong Lee
  • 10,314
  • 25
  • 68
  • 106
  • `img` is, by default, `inline-block`, not `inline`. Which is why you can specify width and margin in the CSS. – David Thomas Nov 20 '13 at 01:05
  • @DavidThomas Thanks. I didn't know about `` being `inline-block` not `inline`. But still, even if I specify width and height on the ``, it doesn't resolve the issue. – Seong Lee Nov 20 '13 at 01:11
  • Can you put img in one div and text in other div, and apply display:inline to both divs? – Murali Mopuru Mar 25 '15 at 07:28

6 Answers6

14

This question seems to be concerned about the why over the how, so I'll focus on the inner-workings:

The Visual formatting model section of the CSS 2.1 spec describes inline formatting contexts:

In an inline formatting context, boxes are laid out horizontally, one after the other, beginning at the top of a containing block. Horizontal margins, borders, and padding are respected between these boxes. The boxes may be aligned vertically in different ways: their bottoms or tops may be aligned, or the baselines of text within them may be aligned. The rectangular area that contains the boxes that form a line is called a line box.

The property they describe is vertical-align which takes a number of different values, baseline being the default. This is why your two inline elements appear as they do, by sitting on the baseline. You could change the <p> to vertical-align: top, and the top of the first line of text will align with the top of the image. However, you will still get a gap between the first line of text and the following lines.

This is because the text is rendering one line-box to the next, vertically. Regardless if the line-box of the first line is larger than the rest, it will still flow one line-box at a time. Here’s a visualization of this concept:

enter image description here

Another important concept in understanding this is that <img> is a replaced inline element, which means its appearance is constructed by an external resource outside of the document. replaced inline elements can take a height value, while so-called non-replaced inline (like a <span>) elements cannot. This is why <img> <span>foo</span> can behave differently than <span>foo</span> <em>bar</em> (because the image has an intrinsic height), even though they are all inline elements. Imagine setting the height of the image to the x-height of the text -- it would effectively render the same as your image, but in this case it behaves exactly as you would expect:

img {
  height: 10px;
  }

p { 
  display: inline;
  }
<div>
    <img src="http://placehold.it/100x100/E8117F/000.png">
    <p>hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello</p>
</div>

This may be where some of the confusion is happening. If you can imagine the lines then you can understand that there is no expectation for inline elements to behave like floated elements.

Compare that information to what the spec says about floats:

A float is a box that is shifted to the left or right on the current line. The most interesting characteristic of a float (or "floated" or "floating" box) is that content may flow along its side (or be prohibited from doing so by the 'clear' property). Content flows down the right side of a left-floated box and down the left side of a right-floated box.

A floated box is shifted to the left or right until its outer edge touches the containing block edge or the outer edge of another float. If there is a line box, the outer top of the floated box is aligned with the top of the current line box.

While I can't describe to you what's happening down to the electron, I hope this is a good starting point in understanding why these different scenarios render how they do.

Community
  • 1
  • 1
zep_fan
  • 776
  • 5
  • 13
  • @coldpumpkin Please feel free to suggest an edit or point out incorrect information. – zep_fan Apr 06 '15 at 23:55
  • The title requested, "make paragraph text wrap around image WITHOUT float". Flexbox might work here, though I'm still having trouble wrapping text while changing browser size without a large white space appearing. – Padawan Apr 19 '15 at 15:20
3

Try making the image absolute, then use the adjacent sibling selector to add padding to the next paragraph tag to compensate for the image. Fiddle here: http://jsfiddle.net/r2MFz/3/

Here's the CSS.

img:first-of-type + p {
  padding-left: 110px;
  display: inline-block;
}

p {
  padding-bottom: 20px;
}

img {
  position: absolute;
  top: 0;
  left: 0;
}

This is getting pretty creative, other than this I can't think of any other option besides float.

jabs83
  • 190
  • 5
2

You need to make the image inline and floating, not the text This has been the way to make images behave since at least '98, maybe earlier but I only started working with a word processor since '98. For some reason the images decide text flow ;-)

img {
    float:left;
    display:inline-block;
    margin:10px;
   
}
<div class="hoge">
    <img src="http://dummyimage.com/100x100/000/fff">
        <p>hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello hello</p>
</div>
Tschallacka
  • 27,901
  • 14
  • 88
  • 133
1

The reason of the whitespace is probably caused by the missing vertical-align property. If you include the vertical-align: top property, the first row of the paragraph will be moved to the top. The only problem is there still is a whitespace.

This is what I mean: http://jsfiddle.net/7t633/5/

CSS

p {
    display: inline;
    vertical-align: top;
}

But if you change the CSS a bit for both the img and p you can achieve a float effect without using the float property. Only thing is that the text won't wrap around the image. You'll have to use the float property to achieve this.

This is what I mean: http://jsfiddle.net/7t633/6/

CSS

img {
    display: inline;
    position: absolute;
}
p {
    display: inline-block;
    margin-left: 105px;
    vertical-align: top;    
}
Hkidd
  • 872
  • 10
  • 25
1

I don't think there's another CSS solution to wrap it without floating. You could absolute-position items but then they would be side-by-side, not wrapping. You could instead try using this jQuery plugin to wrap text. You can even wrap around curved images:

http://baconforme.com/

geochanto
  • 972
  • 2
  • 13
  • 45
1

As you say, you can easily overcome this problem by using float. This article talks about shapes and float, so it's a good reference: How to wrap text around an image using HTML/CSS

Therefore, if you are just asking what causes the whitespace, you're really asking is how does the browser's parsing and rendering processes relate to floats. In short, while tokenization and parsing is more complicated than this, the basic concept remains that the browser is rendering the output onto the screen in a left to right, top to bottom format. Therefore, if you put your image tag first, as an inheritably inline element, it is going to claim as much screen real estate (rendering on the screen) as it needs to in order to display. We rendered left to right, top to bottom, so the last spot the rendering pointer ended was the bottom right of the picture. If you modify the next tag, on the same tree level, to also be inline, it just knows to continue where the image pointer left off. The pointer says, this is where I should start drawing the words in the paragraph tag. Because I know the default values for the paragraph tag, I'm going to jump up and render a letter to the appropriate height and width.

Float fixes this because a floated box is positioned within the normal flow, then taken out of the flow and shifted to the left or right as far as possible. Thus, your pointer for where the paragraph should continue to render changes position.

Here are good sources for that: http://taligarsiel.com/Projects/howbrowserswork1.htm#Parsing_general http://www.smashingmagazine.com/2007/05/01/css-float-theory-things-you-should-know/

Community
  • 1
  • 1
phpmeh
  • 1,752
  • 2
  • 22
  • 41
  • 4
    the title and question is about: wrapping text around an image WITHOUT float. Would you mind updating your answer? – Omar Mar 25 '15 at 02:49