2

With this CSS:

li { margin-top: -1px;   }
li:before { content: "x"; float:left; }

under <!doctype html>, a standard <ul> list shows a shifted pattern:

Why?

Removing margin-top: -1px; or making it positive cancels the effect: the list is shown normally.

Here is a jsfiddle. I checked in FireFox, Chrome, IE.

The list was

<ul>
    <li>y</li>
    <li>y</li>
    <li>y</li>
</ul>

Note: my question is not how to avoid it, but why it happens -- to understand how CSS works.

Alexander Gelbukh
  • 2,104
  • 17
  • 29

5 Answers5

1

The floated elements are clipping / stacking.

Use background: red; on li:before to see it.

Here is the updated fiddle

Either remove the float: left; or the margin-top: -1px to fix it.
I'd suggest both - the float does nothing and instead of the margin-top, you can use line-height.

Imanuel
  • 3,596
  • 4
  • 24
  • 46
  • Wouldn't it be better for you to actually show what you said? And thus actually give a more complete answer ? – Andrew Truckle Jul 23 '17 at 05:58
  • The red color helps indeed to understand what's happening! As to removing things, this is irrevelant: this MWE is taken from a large project where floating was really necessary. – Alexander Gelbukh Jul 23 '17 at 06:32
  • The interesting thing is they all seem to occupy the same space. https://jsfiddle.net/9bp0pkyr/1/ check the borders. They start and end at the same point. – Mohammed Joraid Jul 23 '17 at 06:46
  • You are displaying the border of the `li` items, not the `li:before` that are causing the issue. – Imanuel Jul 23 '17 at 06:47
0

Is there a reason for floating the pseudo element? If you remove or clear the float, it works

li { margin-top: -1px;  }
li:before { content: "x";  }
<ul>
    <li>y</li>
    <li>y</li>
    <li>y</li>
</ul>
itacode
  • 3,721
  • 3
  • 21
  • 23
0

You don't need the float: left or else it considers it as aligning to the left of the end of the previous object

Elisa L
  • 262
  • 1
  • 2
  • 11
0

That's happening because you are using float:left, you just need to remove this property and it will work perfectly fine. Below is the updated code:

li {
  margin-top: -1px;
}

li:before {
  content: "x";
}
<ul>
  <li>y</li>
  <li>y</li>
  <li>y</li>
</ul>
Milan Chheda
  • 8,159
  • 3
  • 20
  • 35
0

Pretty interesting. I think there are a couple of interesting regressions happening because you do margin-top: -1px and you also float a pseudo element inside the <li> which causes some interesting things with the document flow.

Removing one or the other makes it seem to work as expected.

You could also put a clear: both on the :before pseudo element which will specify to the browser that the floating elements shouldn't try to float on the same line. That also seems to help a little.

I actually think the heart of the issue lies with the fact that <li> by default comes with its own "margin-top" with the default style of -webkit-margin-before: 1em. It seems setting li to have a style of -webkit-margin-before: 0em also solves the issue. For more information of -webkit-margin-before, see this answer

In all honesty, I'm still looking into it so I'll try to update my answer if I can. One thing I am looking into is it could be the result of margin-collapsing but I don't have enough evidence to support it.

Specifically this excerpt might suggest a clue:

When negative margins are involved, the size of the collapsed margin is the sum of the largest positive margin and the smallest (most negative) negative margin.

If both are negative, the greater negative value is used. This definition applies to adjacent elements and nested elements.

Margins of floating and absolutely positioned elements never collapse.

Community
  • 1
  • 1
aug
  • 11,138
  • 9
  • 72
  • 93