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
The whole display is constrained to 200px
width, but it scrolls to accommodate longer names.
The problem
However, when scrolling, the highlight does not extend to the full width*. I've tried various combination of nesting div
s and playing with the width
, but no luck. How can I accomplish this?
I'm having trouble with the fact that
- Each item / line has a different width
- 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>