How do I style ul/ols to be able to flexibly wrap around float-ed content?
Asked Answered
C

2

8

I have what I feel like should be a relatively straightforward set of constraints that I can't seem to find a solution to. I'm trying to build a set of WYSIWYG component stylings that will work flexibly together, and can't get a combination of bulleted/numbered lists to wrap predictably around float-ed figures without losing indentation or causing overlapping content:

Restrictions:

  • Nested lists should be indented more with each level of nesting
  • Floating content can float either to right or left side
  • Lists can be arbitrarily long and should wrap predictably around floating content

This is the default styling for a list to the right of content that has "float: left" set. The bullets overlap with the floating content and the indentation is lost.

.pull-left {
  background: #3333ff;
  color: white;
  float: left;
  width: 50%;
  height: 80px;
}
<div class="pull-left">Floating content</div>

<ul>
  <li>First Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
  <li>Second Item</li>
  <li>Third Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
</ul>

Setting a value to overflow (i.e. overflow: hidden) on the <ul> element fixes the bullet formatting + the indentation, but doesn't allow the content to wrap:

.pull-left {
  background: #3333ff;
  color: white;
  float: left;
  width: 50%;
  height: 80px;
}

ul {
  overflow: hidden;
}
<div class="pull-left">Floating content</div>

<ul>
  <li>First Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
  <li>Second Item</li>
  <li>Third Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
</ul>

The only other solution I can think of is to use nested transforms and offset padding to get it to work:

.pull-left {
  background: #3333ff;
  color: white;
  float: left;
  width: 50%;
  height: 80px;
}

ul {
  padding: 0;
}

li {
  list-style-position: inside;
  transform: translateX(30px);
  padding-right: 30px;
}
<div class="pull-left">Floating content</div>

<ul>
  <li>First Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
  <li>Second Item</li>
  <li>Third Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
</ul>

However, this solution doesn't work when the floating content is floating to the right:

.pull-right {
  background: #3333ff;
  color: white;
  float: right;
  width: 50%;
  height: 80px;
}

ul {
  padding: 0;
}

li {
  list-style-position: inside;
  transform: translateX(30px);
  padding-right: 30px;
}
<div class="pull-right">Floating content</div>

<ul>
  <li>First Item
    <ul>
      <li>Nested Item with long enough text that it overlaps the floating content</li>
      <li>Nested Item</li>
    </ul>
  </li>
  <li>Second Item</li>
  <li>Third Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
</ul>

I've scoured the internet for a flexible solution to this and can't find anything anywhere. Is this set of (pretty reasonable) restrictions just not something that can be done? Or am I missing something?

Combust answered 26/9, 2018 at 1:6 Comment(4)
I think you can't do that, you have covered all the cases, but each case invalidated the previous, you could add .pull-right + ul { overflow: hidden; } to the last example, but only would work with that class name.Uboat
@Uboat adding overflow: hidden still prevents the text from wrapping beneath the image, so any longer content in the lower part of the list would wrap unnecessarily with whitespace to the side stillCombust
are all of the floated elements the same width?Kori
Not necessarily, though in my case there's a short list of % widths they can be. They can be any height as well.Combust
P
1

I think you were close with the transform solution but you can probably change it to use text-indent and adjust indentation for each level.

.pull-left {
  background: #3333ff;
  color: white;
  float: left;
  width: 50%;
  height: 80px;
}

ul {
  padding: 0;
}

li {
  list-style-position: inside;
  text-indent: 10px;
  padding-right: 30px;
}

ul ul>li {
  text-indent: 20px;
}

ul ul ul>li {
  text-indent: 30px;
}

ul ul ul ul>li {
  text-indent: 40px;
}
<div class="pull-left">Floating content</div>

<ul>
  <li>First Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item
        <ul>
          <li>Nested Item</li>
          <li>Nested Item</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Second Item</li>
  <li>Third Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
</ul>

It will also be fine with right floating:

.pull-right {
  background: #3333ff;
  color: white;
  float: right;
  width: 50%;
  height: 80px;
}

ul {
  padding: 0;
}

li {
  list-style-position: inside;
  text-indent: 10px;
  padding-right: 30px;
}

ul ul>li {
  text-indent: 20px;
}

ul ul ul>li {
  text-indent: 30px;
}

ul ul ul ul>li {
  text-indent: 40px;
}
<div class="pull-right">Floating content</div>

<ul>
  <li>First Item
    <ul>
      <li>Nested Item long long long long long long long long long text</li>
      <li>Nested Item
        <ul>
          <li>Nested Item with long long long long long long long long long text</li>
          <li>Nested Item</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Second Item</li>
  <li>Third Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
</ul>
Pritchard answered 26/9, 2018 at 10:31 Comment(1)
This is so close to working! Unfortunately, the text in items that wrap all align to the left of the outer list, not to the left of their item.Combust
K
0

Using a combination of margin-left and a negative text-indent works on the float: right box.

.pull-right {
  background: #3333ff;
  color: white;
  float: right;
  width: 50%;
  height: 80px;
}

ul {
  padding: 0;
}

li {
  list-style-position: inside;
  margin-left:10px;
  padding-right: 30px;
}

ul ul>li {
  margin-left: 35px;
  text-indent: -15px;
}

ul ul ul>li {
  margin-left: 45px;
  text-indent: -15px;
}

ul ul ul ul>li {
  margin-left: 55px;
  text-indent: -15px;
}
<div class="pull-right">Floating content</div>

<ul>
  <li>First Item
    <ul>
      <li>Nested Item long long long long long long long long long text</li>
      <li>Nested Item
        <ul>
          <li>Nested Item with long long long long long long long long long text</li>
          <li>Nested Item</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Second Item</li>
  <li>Third Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
</ul>

Unfortunately, it doesn't work with the box floating left. In the worst case scenario, you could put a clear: left on the <ul>. It won't wrap, but nothing weird will happen.

.pull-left {
  background: #3333ff;
  color: white;
  float: left;
  width: 50%;
  height: 80px;
}

ul {
  padding: 0;
  clear: left;
}

li {
  list-style-position: inside;
  margin-left:10px;
  padding-right: 30px;
}

ul ul>li {
  margin-left: 35px;
  text-indent: -15px;
}

ul ul ul>li {
  margin-left: 45px;
  text-indent: -15px;
}

ul ul ul ul>li {
  margin-left: 55px;
  text-indent: -15px;
}
<div class="pull-left">Floating content</div>

<ul>
  <li>First Item
    <ul>
      <li>Nested Item long long long long long long long long long text</li>
      <li>Nested Item
        <ul>
          <li>Nested Item with long long long long long long long long long text</li>
          <li>Nested Item</li>
        </ul>
      </li>
    </ul>
  </li>
  <li>Second Item</li>
  <li>Third Item
    <ul>
      <li>Nested Item</li>
      <li>Nested Item</li>
    </ul>
  </li>
</ul>
Kori answered 26/9, 2018 at 13:8 Comment(1)
Thanks for this! Unfortunately I'm looking for a solution that'll work in both cases without needing to modify markup between them (outside of attaching the correct "float" class to the floating content). The case with the float: right actually works great by default, but I can't find a solution that both fixes the float: left case and doesn't break the float: right oneCombust

© 2022 - 2024 — McMap. All rights reserved.