Home > Software design >  Making a list item take the full width of the parent list
Making a list item take the full width of the parent list

Time:10-01

I'm creating a display that mimics how a directory of files might be displayed in a file browser or IDE (e.g. Sublime, VSCode, etc..)

body {
  font-size: 16px;
  font-family: monospace;
}

.tree {
  box-sizing: border-box;
  min-width: 200px;
  width: 200px;
  height: 400px;
  margin: 0;
  padding: 20px 0;
  overflow-x: scroll;
  white-space: nowrap;
  background-color: #ebedef;
}

.tree-node {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: stretch;
  justify-content: flex-start;
  height: 18px;
  padding: 6px 0;
  cursor: pointer;
}

.tree-node:hover {
  background-color: #dbdde0;
}

.tree-node span {
  line-height: 18px;
}

.tree-node svg {
  margin-right: 7px;
}
<body>
  <ul class="tree">
    <li style="padding-left: 15px;" tabindex="0" class="tree-node tree-node--directory">
      <span>/</span>
    </li>
    <li style="padding-left: 30px;" tabindex="0" class="tree-node tree-node--directory">
      <span>dir1</span>
    </li>
    <li style="padding-left: 45px;" tabindex="0" class="tree-node tree-node--directory">
      <span>dir2</span>
    </li>
    <li style="padding-left: 60px;" tabindex="0" class="tree-node tree-node--file">
      <span>transformations.js</span>
    </li>
    <li style="padding-left: 45px;" tabindex="0" class="tree-node tree-node--file">
      <span>foo.js</span>
    </li>
    <li style="padding-left: 30px;" tabindex="0" class="tree-node tree-node--file">
      <span>package.json</span>
    </li>
  </ul>
</body>

It uses an inline padding-left on each element to indent it as needed to form the file structure.

As you hover over a directory or file (e.g. transformations.js), it is highlighted with a background color

enter image description here

The whole display is constrained to 200px width, but it scrolls to accommodate longer names.

The problem

enter image description here

However, when scrolling, the highlight does not extend to the full width*. I've tried various combination of nesting divs and playing with the width, but no luck. How can I accomplish this?

I'm having trouble with the fact that

  1. Each item / line has a different width
  2. Each item / line has a custom padding-left set as an offset

I'm open to refactoring the structure in any way needed to make this work visually.

Thanks!

CodePudding user response:

You can apply width calculations for each level. This gets your styles out of your markup, too.

body {
  font-size: 16px;
  font-family: monospace;
}

.tree {
  min-width: 200px;
  width: 200px;
  height: 150px;
  margin: 0;
  padding: 20px 0;
  overflow-x: scroll;
  white-space: nowrap;
  background-color: #ebedef;
}

.tree-node {
  width: calc(100%   15px);
  height: 18px;
  padding: 6px 0;
  cursor: pointer;
  background: pink;
}

.tree-node.level-1 {
  padding-left: 15px;
  width: calc(100%   75px);
}

.tree-node.level-2 {
  padding-left: 30px;
  width: calc(100%   60px);
}

.tree-node.level-3 {
  padding-left: 45px;
  width: calc(100%   45px);
}

.tree-node.level-4 {
  padding-left: 60px;
  width: calc(100%   30px);
}

.tree-node:hover {
  background-color: #dbdde0;
}

.tree-node span {
  line-height: 18px;
}

.tree-node svg {
  margin-right: 7px;
}
<body>
  <ul class="tree">
    <li tabindex="0" class="tree-node level-1 tree-node--directory">
      <span>/</span>
    </li>
    <li tabindex="0" class="tree-node level-2 tree-node--directory">
      <span>dir1</span>
    </li>
    <li tabindex="0" class="tree-node level-3 tree-node--directory">
      <span>dir2</span>
    </li>
    <li tabindex="0" class="tree-node level-4 tree-node--file">
      <span>transformations.js</span>
    </li>
  </ul>
</body>

CodePudding user response:

I would suggest to use display: block instead of display: flex and to add the padding to the spans. The problem is that the .tree doesn't cover the whole container but without the scroll. I couldn't find a solution without Javascript.

const container = document.querySelector('.container');
const tree = document.querySelector('.tree');
tree.style.width = container.scrollWidth   'px';
body {
  font-size: 16px;
  font-family: monospace;
}
.container{
    min-width: 200px;
  width: 200px; 
    overflow-x: scroll;
    background-color: #ebedef;
}
.tree {
  box-sizing: border-box;
  list-style-type: none;
  height: 400px;
  margin: 0;
  padding: 20px 0;
  display: block;
}

.tree-node {
  display: block;
  height: 18px;
  padding: 6px 0;
  cursor: pointer;
}
.tree-node:hover {
  background-color: #dbdde0;
}

span {
  line-height: 18px;
  display:block;
}
svg {
  margin-right: 7px;
}
<div class="container">
  <ul class="tree">
    <li tabindex="0" class="tree-node tree-node--directory">
      <span style="padding-left: 15px;">/</span>
    </li>
    <li tabindex="0" class="tree-node tree-node--directory">
      <span >dir1</span>
    </li>
    <li tabindex="0" class="tree-node tree-node--directory">
      <span style="padding-left: 45px;">dir2</span>
    </li>
    <li tabindex="0" class="tree-node tree-node--file">
      <span style="padding-left: 60px;">transformations.js</span>
    </li>
    <li tabindex="0" class="tree-node tree-node--file">
      <span style="padding-left: 45px;">foo.js</span>
    </li>
    <li tabindex="0" class="tree-node tree-node--file">
      <span style="padding-left: 30px;">package.json</span>
    </li>
  </ul>
</div>

CodePudding user response:

You just need to provide width: 100%; to the li element and you are good to go. It will work exactly as you want it to. You can either use nth-child selector or you can just do it for all of the li elements so that each element has the same behaviour.

If you want to do it using javascript then it would be a little easier. What you need to do is

// Get the scroll width of your ul
const scrollWidth = document.querySelector("ul.tree").scrollWidth;
// Now select the li element or all of them and put them in a loop 
// for now I'm doing it for the first one just for simplicity
// but the same goes for all of the others
const element = document.querySelector("li");

element.style.width = scrollWidth   "px";
// You can console log scroll width to see what it outputs

Another way using css You have to do it separately for different elements. For example, the elements with 30px padding can have one rule but the ones with 60px padding on left will have slight change in it

/* select the particular li element */
/* in this case assume I have given p-30 class to all elements with 30px of padding */

.p-30 {
   width: calc(100%   30px);
}

CodePudding user response:

Simply add display:grid to tree element. You may need to also adjust the alignment:

body {
  font-size: 16px;
  font-family: monospace;
}

.tree {
  box-sizing: border-box;
  min-width: 200px;
  width: 200px;
  height: 400px;
  margin: 0;
  padding: 20px 0;
  overflow-x: scroll;
  white-space: nowrap;
  background-color: #ebedef;
  /* added */
  display:grid;
  align-content:flex-start;
  /**/
}

.tree-node {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: stretch;
  justify-content: flex-start;
  height: 18px;
  padding: 6px 0;
  cursor: pointer;
}

.tree-node:hover {
  background-color: #dbdde0;
}

.tree-node span {
  line-height: 18px;
}

.tree-node svg {
  margin-right: 7px;
}
<body>
  <ul class="tree">
    <li style="padding-left: 15px;" tabindex="0" class="tree-node tree-node--directory">
      <span>/</span>
    </li>
    <li style="padding-left: 30px;" tabindex="0" class="tree-node tree-node--directory">
      <span>dir1</span>
    </li>
    <li style="padding-left: 45px;" tabindex="0" class="tree-node tree-node--directory">
      <span>dir2</span>
    </li>
    <li style="padding-left: 60px;" tabindex="0" class="tree-node tree-node--file">
      <span>transformations.js</span>
    </li>
    <li style="padding-left: 45px;" tabindex="0" class="tree-node tree-node--file">
      <span>foo.js</span>
    </li>
    <li style="padding-left: 30px;" tabindex="0" class="tree-node tree-node--file">
      <span>package.json</span>
    </li>
  </ul>
</body>

  • Related