Responsive Separator for Horizontal List - html

This question expands upon 'Separators For Navigation' by asking, how it is possible to remove the separators at the line breaks cause by viewport size.
Wide Viewport
-> Item 1 | Item 2 | Item 3 | Item 4 | Item 5 <-
Small Viewport
-> Item 1 | Item 2 | Item 3 <-
-> Item 4 | Item 5 <-
Here is a fiddle that shows how a pipe remains at the line break:
Fiddle.
I'm interested in a css-only solution, but javascript is acceptable if it provides the only possible solution.

Explanation
You can exploit fact that trailing and line trailing white space automatically collapses:
document.write(
'word<b style="background: red; outline: 1px solid blue;"> </b>'
.repeat(42)
);
As you can see there are red spaces with blue outlines between words, but the very last and and two at line ends lack the red area because it's width collapsed to zero: that is the white-space collapsing in effect.
It is possible to adjust width with word-spacing and use pseudo element instead, so setting inline ::after { content: ' '; word-spacing: 2em; } gives you wide inline rectangle that can have decorated backgrounds or borders but disappears when it is not between words.
Simplified example
Simplified use case (from https://codepen.io/myf/pen/dyOzpZM, tested just in 2021-02 evergreen Firefox and Chromium, will not work in pre-Chromium Edge; for more robust example see the second snippet below):
ul {
text-align: center;
padding: 0;
}
li {
display: inline;
}
li::after {
/*
This has to be space, tab or other
breakable white-space character:
*/
content: " ";
word-spacing: 1em;
background-image: linear-gradient(
-0.2turn,
transparent 0 calc(50% - 0.03em),
currentcolor 0 calc(50% + 0.03em),
transparent 0
);
}
/*
That's it: just inline text
with styled ::after spaces
that collapse at line breaks
and at the end of the element.
That's basically how spaces work in text.
*/
/*
Unrelated whimsical effects:
*/
body { background: #456; color: #fed; min-height: 100vh; margin: 0; display: flex; align-items: center; }
ul { --dur: 3s; font-family: Georgia, serif; font-size: min(7vw, calc(100vh / 7)); margin: 0 auto; position: relative; padding: 0 1em; -webkit-text-fill-color: #999; text-transform: capitalize; animation: poing var(--dur) infinite alternate ease-in-out; }
#keyframes poing { from { max-width: 3.4em; } to { max-width: min(19em, calc(100vw - 2em)); color: lime; } }
ul::before, ul::after { -webkit-text-fill-color: currentcolor; position: absolute; top: 50%; transform: translatey(-50%); animation: calc(var(--dur) * 2) calc(var(--dur) * -1.5) infinite forwards linear; }
ul::before { content: "☜"; left: 0; animation-name: a !important; }
ul::after { content: "☞"; right: 0; animation-name: b !important; }
#keyframes a { 50% { content: "☛"; } }
#keyframes b { 50% { content: "☚"; } }
ul:hover, ul:hover::before, ul:hover::after { animation-play-state: paused; }
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
<li>gazonk</li>
<li>qux</li>
<li>quux</li>
</ul>
It uses flat list with single word items, so is not very relevant for real-world usage.
More realistic example with elements highlights
nav {
text-align: center;
padding-right: 1em; /* = li::after#word-spacing */
}
ul {
display: inline;
margin: 0;
padding: 0;
}
li {
display: inline;
/*
white-space: nowrap should be moved to child A
because IE fails to wrap resulting list completely
*/
}
li::before {
content: ' ';
/*
this content is important only for Chrome in case
the HTML will be minified with *no whitespaces* between </li><li>
*/
}
li::after {
content: ' ';
/*
this is actual placeholder for background-image
and it really must be space (or tab)
*/
white-space: normal;
word-spacing: 1em;
/*
= nav#padding-right - this actually makes width
*/
background-image: radial-gradient(circle, black, black 7%, transparent 15%, transparent 35%, black 45%, black 48%, transparent 55%);
background-size: 1em 1em;
background-repeat: no-repeat;
background-position: center center;
opacity: 0.5;
}
/*
no need to unset content of li:last-child::after
because last (trailing) space collapses anyway
*/
a {
white-space: nowrap;
display: inline-block; /* for padding */
padding: 1em;
text-decoration: none;
color: black;
transition-property: background-color;
transition-duration: 500ms;
}
a:hover {
background-color: #ccc;
}
/*
For demonstrative purposes only
Give items some content and uneven width
*/
nav:hover > ul > li {
outline: 3px dotted rgba(0,0,255,.5);
outline-offset: -3px;
}
nav:hover > ul > li::after {
opacity: 1;
background-color: rgba(255, 0, 0, .5);
}
nav:hover > ul > li:hover {
outline-style: solid;
}
nav:hover > ul > li:hover::after {
background-color: cyan;
}
nav:hover > ul > li > a {
outline: 3px solid rgba(0,255,0,.5);
outline-offset: -3px;
}
nav > ul {
counter-reset: c;
}
nav > ul > li {
counter-increment: c;
}
nav > ul > li > a::before {
content: counter(c, upper-roman) '. ';
letter-spacing: .3em;
}
nav > ul > li > a::after {
content: ' item ' counter(c, lower-roman);
word-spacing: .3em;
letter-spacing: .1em;
transform: translatex(.1em);
display: inline-block;
}
<nav>
<ul><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
</ul>
</nav>
<!-- For demonstrative purposes is content of links made by CSS
-->
(Originally from https://jsfiddle.net/vnudrsh6/7/) This proof-of-concept uses background-image of "eventually colapsing" CSS generated content space after each <li>. Tested in 2016 in Firefox, Chrome and IE11.
Obviously you might need to use some character or more complex shape as divider. Naturally you can use (vector) background-image, and you can even use text in SVG, although making it correspond with surrounding ("real") text might be quite daunting.
Bare-bones with SVG
Minimal working example without any "list" element, with textual ❦ fleuron:
body {
text-align: center;
}
b::after {
content: " ";
word-spacing: 16px;
background: url("data:image/svg+xml;charset=utf-8,\
<svg xmlns='http://www.w3.org/2000/svg' \
viewBox='-3,-15,16,16'>\
<text>❦</text>\
</svg>");
}
<b>foo</b> <b>bar</b> <b>baz</b> <b>gazonk</b> <b>qux</b> <b>quux</b>
<b>foo</b> <b>bar</b> <b>baz</b> <b>gazonk</b> <b>qux</b> <b>quux</b>
<b>foo</b> <b>bar</b> <b>baz</b> <b>gazonk</b> <b>qux</b> <b>quux</b>
Other notable answers:
Same technique used in overlooked Liphtier's answer from 2014. (I've found that one long after posting this answer, so to my disappointment I cannot claim my answer is was first.)
Same technique used in few months younger Tom Robinson's answer.
gfullam's answer using flex-box, very impressive alternative with plain over-extending borders and different spacing due flex arrangement.
Oriol's answer for left-aligned list using overflow hidden and real character in pseudo.

A different solution from that same CSS: Last element on line seems like it would work here.
HTML:
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
CSS:
div {overflow: hidden; margin: 1em; }
div ul { list-style: none; padding: 0; margin-left: -4px; }
div ul li { display: inline; white-space: nowrap; }
div ul li:before { content: " | "; }
(Fiddle)

If you have static width of your element you can calculate by the media-screen.
If not use script
body {
text-align: center;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block;
&:not(:last-child):after {
content: ' |';
}
}
#media screen and (max-width: 265px) {
li {
display: inline-block;
&:not(:last-child):after {
content: '';
}
}
}

Nice question. For the life of me, I can't think of a water-tight CSS-only solution I'm afraid...
I've modified an old solution to a similar question posted a while back: CSS: Last element on line. Funnily enough I was looking for a solution to another problem I had a while back and stumbled across this - been bookmarked since!
Here's a fiddle with my updates: https://jsfiddle.net/u2zyt3vw/1/
HTML:
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
CSS:
body {
text-align: center;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block;
&:not(:last-child):after {
content: ' |'
}
}
li.remove:after {
content: none;
}
jQuery:
$(window).on("resize", function () {
var lastElement = false;
$("ul > li").each(function() {
if (lastElement && lastElement.offset().top != $(this).offset().top) {
lastElement.addClass("remove");
}
lastElement = $(this);
}).last().addClass("remove");
}).resize();
NOTE - it works best onload at the moment, resizing causes a few issue even if I use toggleClass(). So keep pressing "Run" every time you resize the view. I'll work on it and get back to you..

My implementation with JavaScript: https://jsfiddle.net/u2zyt3vw/5/
Hit "Run" again after you've resized the window.
You can also add event listeners such as onresize. Here's the JS:
var listItems = document.getElementsByTagName("li");
var listItemsWidth = [];
var listItemsDistance = [];
for (let i = 0; i < listItems.length; i++) {
listItemsWidth[i] = listItems[i].offsetWidth;
listItemsDistance[i] = listItems[i].getBoundingClientRect().right;
}
for (let i = 0; i < listItems.length; i++) {
if (listItemsDistance[i] == Math.max.apply(null, listItemsDistance)) {
listItems[i].classList -= "notLast";
} else {
listItems[i].classList = "notLast";
}
}
I added the notLast class to all of your elements, and that's what contains the :after pseudo-element with the pipe. This script removes this class from the ones that are closer to the right edge of the container.
I also messed around with the :after pseudo-element and made it position:absolute; for dark reasons.

Related

How to insert separator between items except when wrapped (in CSS)? [duplicate]

This question expands upon 'Separators For Navigation' by asking, how it is possible to remove the separators at the line breaks cause by viewport size.
Wide Viewport
-> Item 1 | Item 2 | Item 3 | Item 4 | Item 5 <-
Small Viewport
-> Item 1 | Item 2 | Item 3 <-
-> Item 4 | Item 5 <-
Here is a fiddle that shows how a pipe remains at the line break:
Fiddle.
I'm interested in a css-only solution, but javascript is acceptable if it provides the only possible solution.
Explanation
You can exploit fact that trailing and line trailing white space automatically collapses:
document.write(
'word<b style="background: red; outline: 1px solid blue;"> </b>'
.repeat(42)
);
As you can see there are red spaces with blue outlines between words, but the very last and and two at line ends lack the red area because it's width collapsed to zero: that is the white-space collapsing in effect.
It is possible to adjust width with word-spacing and use pseudo element instead, so setting inline ::after { content: ' '; word-spacing: 2em; } gives you wide inline rectangle that can have decorated backgrounds or borders but disappears when it is not between words.
Simplified example
Simplified use case (from https://codepen.io/myf/pen/dyOzpZM, tested just in 2021-02 evergreen Firefox and Chromium, will not work in pre-Chromium Edge; for more robust example see the second snippet below):
ul {
text-align: center;
padding: 0;
}
li {
display: inline;
}
li::after {
/*
This has to be space, tab or other
breakable white-space character:
*/
content: " ";
word-spacing: 1em;
background-image: linear-gradient(
-0.2turn,
transparent 0 calc(50% - 0.03em),
currentcolor 0 calc(50% + 0.03em),
transparent 0
);
}
/*
That's it: just inline text
with styled ::after spaces
that collapse at line breaks
and at the end of the element.
That's basically how spaces work in text.
*/
/*
Unrelated whimsical effects:
*/
body { background: #456; color: #fed; min-height: 100vh; margin: 0; display: flex; align-items: center; }
ul { --dur: 3s; font-family: Georgia, serif; font-size: min(7vw, calc(100vh / 7)); margin: 0 auto; position: relative; padding: 0 1em; -webkit-text-fill-color: #999; text-transform: capitalize; animation: poing var(--dur) infinite alternate ease-in-out; }
#keyframes poing { from { max-width: 3.4em; } to { max-width: min(19em, calc(100vw - 2em)); color: lime; } }
ul::before, ul::after { -webkit-text-fill-color: currentcolor; position: absolute; top: 50%; transform: translatey(-50%); animation: calc(var(--dur) * 2) calc(var(--dur) * -1.5) infinite forwards linear; }
ul::before { content: "☜"; left: 0; animation-name: a !important; }
ul::after { content: "☞"; right: 0; animation-name: b !important; }
#keyframes a { 50% { content: "☛"; } }
#keyframes b { 50% { content: "☚"; } }
ul:hover, ul:hover::before, ul:hover::after { animation-play-state: paused; }
<ul>
<li>foo</li>
<li>bar</li>
<li>baz</li>
<li>gazonk</li>
<li>qux</li>
<li>quux</li>
</ul>
It uses flat list with single word items, so is not very relevant for real-world usage.
More realistic example with elements highlights
nav {
text-align: center;
padding-right: 1em; /* = li::after#word-spacing */
}
ul {
display: inline;
margin: 0;
padding: 0;
}
li {
display: inline;
/*
white-space: nowrap should be moved to child A
because IE fails to wrap resulting list completely
*/
}
li::before {
content: ' ';
/*
this content is important only for Chrome in case
the HTML will be minified with *no whitespaces* between </li><li>
*/
}
li::after {
content: ' ';
/*
this is actual placeholder for background-image
and it really must be space (or tab)
*/
white-space: normal;
word-spacing: 1em;
/*
= nav#padding-right - this actually makes width
*/
background-image: radial-gradient(circle, black, black 7%, transparent 15%, transparent 35%, black 45%, black 48%, transparent 55%);
background-size: 1em 1em;
background-repeat: no-repeat;
background-position: center center;
opacity: 0.5;
}
/*
no need to unset content of li:last-child::after
because last (trailing) space collapses anyway
*/
a {
white-space: nowrap;
display: inline-block; /* for padding */
padding: 1em;
text-decoration: none;
color: black;
transition-property: background-color;
transition-duration: 500ms;
}
a:hover {
background-color: #ccc;
}
/*
For demonstrative purposes only
Give items some content and uneven width
*/
nav:hover > ul > li {
outline: 3px dotted rgba(0,0,255,.5);
outline-offset: -3px;
}
nav:hover > ul > li::after {
opacity: 1;
background-color: rgba(255, 0, 0, .5);
}
nav:hover > ul > li:hover {
outline-style: solid;
}
nav:hover > ul > li:hover::after {
background-color: cyan;
}
nav:hover > ul > li > a {
outline: 3px solid rgba(0,255,0,.5);
outline-offset: -3px;
}
nav > ul {
counter-reset: c;
}
nav > ul > li {
counter-increment: c;
}
nav > ul > li > a::before {
content: counter(c, upper-roman) '. ';
letter-spacing: .3em;
}
nav > ul > li > a::after {
content: ' item ' counter(c, lower-roman);
word-spacing: .3em;
letter-spacing: .1em;
transform: translatex(.1em);
display: inline-block;
}
<nav>
<ul><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
</ul>
</nav>
<!-- For demonstrative purposes is content of links made by CSS
-->
(Originally from https://jsfiddle.net/vnudrsh6/7/) This proof-of-concept uses background-image of "eventually colapsing" CSS generated content space after each <li>. Tested in 2016 in Firefox, Chrome and IE11.
Obviously you might need to use some character or more complex shape as divider. Naturally you can use (vector) background-image, and you can even use text in SVG, although making it correspond with surrounding ("real") text might be quite daunting.
Bare-bones with SVG
Minimal working example without any "list" element, with textual ❦ fleuron:
body {
text-align: center;
}
b::after {
content: " ";
word-spacing: 16px;
background: url("data:image/svg+xml;charset=utf-8,\
<svg xmlns='http://www.w3.org/2000/svg' \
viewBox='-3,-15,16,16'>\
<text>❦</text>\
</svg>");
}
<b>foo</b> <b>bar</b> <b>baz</b> <b>gazonk</b> <b>qux</b> <b>quux</b>
<b>foo</b> <b>bar</b> <b>baz</b> <b>gazonk</b> <b>qux</b> <b>quux</b>
<b>foo</b> <b>bar</b> <b>baz</b> <b>gazonk</b> <b>qux</b> <b>quux</b>
Other notable answers:
Same technique used in overlooked Liphtier's answer from 2014. (I've found that one long after posting this answer, so to my disappointment I cannot claim my answer is was first.)
Same technique used in few months younger Tom Robinson's answer.
gfullam's answer using flex-box, very impressive alternative with plain over-extending borders and different spacing due flex arrangement.
Oriol's answer for left-aligned list using overflow hidden and real character in pseudo.
A different solution from that same CSS: Last element on line seems like it would work here.
HTML:
<div>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</div>
CSS:
div {overflow: hidden; margin: 1em; }
div ul { list-style: none; padding: 0; margin-left: -4px; }
div ul li { display: inline; white-space: nowrap; }
div ul li:before { content: " | "; }
(Fiddle)
If you have static width of your element you can calculate by the media-screen.
If not use script
body {
text-align: center;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block;
&:not(:last-child):after {
content: ' |';
}
}
#media screen and (max-width: 265px) {
li {
display: inline-block;
&:not(:last-child):after {
content: '';
}
}
}
Nice question. For the life of me, I can't think of a water-tight CSS-only solution I'm afraid...
I've modified an old solution to a similar question posted a while back: CSS: Last element on line. Funnily enough I was looking for a solution to another problem I had a while back and stumbled across this - been bookmarked since!
Here's a fiddle with my updates: https://jsfiddle.net/u2zyt3vw/1/
HTML:
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
CSS:
body {
text-align: center;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
display: inline-block;
&:not(:last-child):after {
content: ' |'
}
}
li.remove:after {
content: none;
}
jQuery:
$(window).on("resize", function () {
var lastElement = false;
$("ul > li").each(function() {
if (lastElement && lastElement.offset().top != $(this).offset().top) {
lastElement.addClass("remove");
}
lastElement = $(this);
}).last().addClass("remove");
}).resize();
NOTE - it works best onload at the moment, resizing causes a few issue even if I use toggleClass(). So keep pressing "Run" every time you resize the view. I'll work on it and get back to you..
My implementation with JavaScript: https://jsfiddle.net/u2zyt3vw/5/
Hit "Run" again after you've resized the window.
You can also add event listeners such as onresize. Here's the JS:
var listItems = document.getElementsByTagName("li");
var listItemsWidth = [];
var listItemsDistance = [];
for (let i = 0; i < listItems.length; i++) {
listItemsWidth[i] = listItems[i].offsetWidth;
listItemsDistance[i] = listItems[i].getBoundingClientRect().right;
}
for (let i = 0; i < listItems.length; i++) {
if (listItemsDistance[i] == Math.max.apply(null, listItemsDistance)) {
listItems[i].classList -= "notLast";
} else {
listItems[i].classList = "notLast";
}
}
I added the notLast class to all of your elements, and that's what contains the :after pseudo-element with the pipe. This script removes this class from the ones that are closer to the right edge of the container.
I also messed around with the :after pseudo-element and made it position:absolute; for dark reasons.

Responsive tree diagram

I'm trying to make a responsive organization chart on desktop and mobile but I'm facing a problem with my code. My diagram exceeds the size of the screen and doesn't display a scroll to see the rest of the diagram as you can see on the image below. Is there a way to put my diagram in a bootstrap container and also if there is a css framework to make diagrams more easily ?
here is the css code used as well as the html code
.tree,
.tree ul,
.tree li {
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
.tree {
margin: 0 0 1em;
text-align: center;
}
.tree,
.tree ul {
display: table;
}
.tree ul {
width: 100%;
}
.tree li {
display: table-cell;
padding: .5em 0;
vertical-align: top;
}
.tree li:before {
outline: solid 1px #666;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
}
.tree li:first-child:before {
left: 50%;
}
.tree li:last-child:before {
right: 50%;
}
.tree code,
.tree span {
display: inline-block;
margin: 0 .2em .5em;
padding: 3.7em .5em;
position: relative;
height: 150px;
width: 150px;
border-radius: 50%;
background-color: #fefefe;
}
.lineh {
margin-top: -9px !important;
margin-bottom: 0px !important;
border: 0 !important;
border-top: 2px solid !important;
width: 159px;
}
.minus-space {
margin-top: 10px !important;
}
.tree span i {
font-size: 40px
}
.tree span.level1 {
background-color: #1e1e1e;
color: yellow;
padding: 2em .5em !important;
}
.tree span.level2 {
background-color: #ffcc01;
padding: 2em .5em !important;
}
.tree span.linev {
background-color: #666 !important;
width: 2px !important;
border-radius: 0% !important;
padding: 0px !important;
margin: 0px !important;
}
.tree ul:before,
.tree code:before,
.tree span:before {
outline: solid 1px #666;
content: "";
height: .5em;
left: 50%;
position: absolute;
}
.tree ul:before {
top: -.5em;
}
.tree code:before,
.tree span:before {
top: -.55em;
}
.tree>li {
margin-top: 0;
}
.tree>li:before,
.tree>li:after,
.tree>li>code:before,
.tree>li>span:before {
outline: none;
}
<div class="container-fluid">
<ul class="tree">
<li><span class="level1"><i class="mdi mdi-bank"></i><br><b>Group board</b></span>
<ul>
<li><span class="level2"><i class="mdi mdi-bank"></i><br><b>Board committees</b></span>
<ul>
<li> <span>Audit</span>
</li>
<li> <span>Remuneration and human ressources</span>
</li>
<li> <span class="linev"></span>
<ul>
<li> <span class="level2"><i class="mdi mdi-bank"></i><br><b>Compliance
committees</b></span>
</li>
<li> <span class="linev"></span>
<ul>
<li><span>Group searching</span></li>
<li><span>Group operation</span></li>
<li><span>Strategic talent</span></li>
<li><span>Group treasure</span></li>
<li><span>Group transformation</span></li>
</ul>
</li>
<li> <span class="level2"><i class="mdi mdi-bank"></i><br><b>Executive
committees</b></span>
</li>
</ul>
</li>
<li> <span>Social ethics</span>
</li>
<li> <span>Nominations</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
Thank you for all your suggestions
For this answer I used some 'CSS only' flowchart code I had lying around. This code is fully responsive and designed to be multipurpose and reusable. Actually, I took the code and basically rewrote it to make it meet your requirements and more developer readable (than only me).
Instead of UL/LI and specific .classes the CSS mainly uses <tag> independend data-* attributes, which, generally speaking, have lower precedence than .classes making them easy to override. data-* attributes are also very easy to access from Javascript.
For positioning and responsiveness, the code heavily relies on flexbox layout.
The code is fully commented, including:
Specifications, how to use the data attributes data-chart, data-knot ('branch','node','step') and data-symbol.
Explanation of the algebra used, definition of a straight line: 'y=mx+b', for responsiveness and scaling of font-size's, width's, height's and spacing (padding, margin). You can find a comprehensible reference on mathisfun (no affiliate).
Rules split after functionality (mechanism vs. styling), for easy extension and theming.
A few tips, alternative uses, quirks (IE11).
Some eye-candy, just because I could...
brief summary
data-chart the type of chart used, only "OC" (Organisation Chart) for now.
data-knot designates the connection type used between data-symbols.
data-knot="branch" (container)
data-knot="node" (horizontal line)
data-knot="step" (vertical line)
data-knot="node.step" (cross line)
data-symbol container holding graphics and text depicting some organisational function. Currently only a colored circle, but can be extended to hold more content (e.g. collapsible card, its original use).
'Landingpage' like responsive page spacing [band] (8px on a 320px screen, 320px on a 1920px screen).
Document reading direction [dir="ltr"] vs. [dir="rtl"] ready (used in <body>).
Two debugging helper rules outlines and hover (used in <body>).
Various kinds of nesting and tree constructions are possible, the one shown here fully matches the responsive chart the OP required/requested (for as far I understood...).
Special care has been taken to fit the chart on a '360x640px' smartphone (portrait) as well as on a "1920x1200px" desktop display (landscape, my own 24").
For now, this code is ONLY available from this Stackoverflow Question. A (more elaborate) codepen version is underway...
note
It might well be possible that you utterly dislike what I did with the code or simply have other requirements than I interpreted. In that case do not downvote the answer, but simply ignore it, as others may find it usefull nonetheless.
extra 'ERS linear equations'
The online tool I created on GeoGebra, ERS linear equations, will hugely simplify finding the proper responsiveness equations for your CSS calc() functions. The tool shows 4 predefined functions of the equations used in the code. Make sure you give it a go (no affiliate, personal work, free, fork it, use it, abuse it)...
The code in the snippet was tested to work on W10 with Chrome, Edge, Firefox and IE11 (+IE10 mode) and on Android 9+ with the default browser and Firefox. For lack of devices, no Apple results.
/******************************/
/* general global preferences */
/******************************/
html,body { box-sizing: border-box } /* [MANDATORY] all size calcs must include padding and border */
*::before,*::after, * { box-sizing: inherit } /* [MANDATORY], ditto, but it WILL inherit any changes */
/*
responsive fontsize:
p1(320,14) p2(1280,20) => 0.00625x + 12
Assumes 16px browser default fontsize and uses
REM to adapt to user modified font settings
In the remainder of this <style> sheet you will find
an explanation of the algebra used in this document.
*/
html { font-size: calc(0.625vmin + 0.75rem) }
body { width: 100%; height: 100%; margin: 0; cursor: default;
font-size: 1rem;
font-family: Roboto,Arial,Helvetica,sans-serif;
background-color: Gainsboro; color: black }
h1 { font-size: 2rem } /* Override of FF+ default nesting behaviour */
/* generic flexbox shortcuts */
[F] { display: flex }
[R] { flex-direction: row } /* horizontal: row of 1:N columns (FBL default) */
[C] { flex-direction: column } /* vertical: column of 1:N rows */
[W] { flex-wrap: wrap }
/* Prevents (inadverted) text selection by user (when double, double clicking) */
[no-select] { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none;
user-select: none; -moz-appearance : none; -webkit-appearance: none }
/* Show element outlines for debugging (use in <body> tag) */
[outlines="1"] * { outline: 1px dashed purple }
/* Color to show nesting level for debugging (use in <body> tag) */
[hover="1"] :not(section) :hover { background-color: rgba(255,0,0,.2) }
/*
KNOT LOGIC
'branch' - 1:N 'node',1:N 'node.step' and 1:N 'step'
'node' - 1:N 'node' and 1:N 'step'
'step' - 1 data-symbol
You can use flexbox shortcut attributes R (horizontal) and C (vertical) to
determine the nesting direction of 'branch'es and 'node's. (R) is optional
as horizontal is the default direction.
(Depending on orientation of the knots, all kinds of nestings might work,
but that will require trial and error, fiddling.)
SPECIFICATIONS
1) 'branch' has no specific rules, but acts as a container for 'node's
and to distinguish from 'node' and 'step'.
Add your own rules for specific 'branch' styling like fonts,colors,border,spacing.
2) 'node' and 'step' only use :before and :after to position and draw
connecting lines.
'node' horizontal line attachement
'step' vertical
'node.step' both
3) 'node.step' can be empty (no 'data-symbol'), in which case it will only
draw cross lines.
4) 'start' and 'stop' values are used to prevent drawing of
starting and ending lines.
5) Knot 'lft', 'ctr' and 'rgt' values define how sibling nodes are connected
'lft' - left hand node, only one
'ctr' - center nodes, can be more than one
'rgt' - right hand node, only one
My motivation for use of 'data-* attributes' instead of classes is they
are easy accessible as javascript variables:
someElement.dataset.chart
someElement.dataset.knot
someElement.dataset.symbol
*/
/***************/
/* Chart Setup */
/***************/
/* If you want the knots distributed as-is, remove 'align-items' */
[data-chart] { display: flex; align-items: center } /* [OPTIONAL], try! */
[data-knot] { display: flex; flex-grow: 1 } /* [MANDATORY] */
/* default alignments */
[data-knot] { justify-content: center }
[data-knot*="node"] { align-items: stretch }
[data-knot*="step"] { align-items: flex-start }
/* this code keeps the lines connect to the symbols */
[data-knot] { position: relative; z-index: 1 } /* new stacking context */
[data-knot]:before,
[data-knot]:after { position: absolute; z-index: -1; content: '' }
/* put some character in 'content' to keep track when debugging */
/* Horizontal lines ('node') setup */
[data-knot]:before { top : 1px } /* adjust -+1 for thickess of outlines */
[data-knot]:after { bottom: -1px }
[data-knot*="node"]:before,[data-knot*="node"]:after
{ height: 0px /* for IE11 */; width: 50% }
/* Vertical lines ('step') setup */
[data-knot*="step"]:before,[data-knot*="step"]:after
{ width: 0px /* for IE11 */; left: 50%; right: 50% }
/* positioning of the lines ('lft','ctr','rgt') */
[data-knot*="ctr"]:before,[data-knot*="ctr"]:after
{ width: 100%; left: 0 }
/* (EITHER) Handles document reading direction (dir="ltr" in <body>) */
[dir="ltr"] [data-knot*="lft"]:before, [dir="ltr"] [data-knot*="lft"]:after { left : 50% }
[dir="ltr"] [data-knot*="rgt"]:before, [dir="ltr"] [data-knot*="rgt"]:after { right: 50% }
[dir="rtl"] [data-knot*="lft"]:before, [dir="rtl"] [data-knot*="lft"]:after { right: 50% }
[dir="rtl"] [data-knot*="rgt"]:before, [dir="rtl"] [data-knot*="rgt"]:after { left : 50% }
/* (OR) For use without [dir]
[data-knot*="lft"]:before, [data-knot*="lft"]:after { left : 50% }
[data-knot*="rgt"]:before, [data-knot*="rgt"]:after { right: 50% }
*/
/* line coloring */
[data-knot*="node"]:before,[data-knot*="node.step"]:after,
[data-knot*="step"]:before,[data-knot*="step"]:after { outline: 1px solid #666 }
/* no line drawing cases */
[data-knot="step"]:after, /* notice the missing '*' */
[data-knot*="start"]:before ,[data-knot*="stop"]:after { outline: none }
/*
responsive sizes: T/B p1(320,6) p2(1280,24) and L/R p1(320,4) p2(1280,16)
modify these to meet specific requirements.
*/
[data-knot*="step"] { padding: 1.875vmin 1.25vmin }
[data-knot*="step"]:before { height : 1.875vmin } /* Same height as [data-step] T/B padding */
[data-knot*="step"]:after { height : calc(100% - 1.875vmin) } /* pct to from below (minus T/B padding) */
/****************/
/* Symbol Setup */
/****************/
/*
Chart 'data-symbol's, flexbox intended use
FBL (V) FBL (H) Any
-------- ------- -------
(S)ymbol -> (H)eader -> content
-> (C)ontent -> content
-> (F)ooter -> content
*/
[data-symbol],
[data-symbol]>* { display: flex } /* S,H,C,F are flexbox parent containers */
[data-symbol]>*>* { flex-grow: 1 } /* sets default to 'fill' for content of H,C,F */
[data-symbol] { flex-direction: column } /* a column of 1:N rows */
[data-symbol]>.header { align-items: center }
/* styling */
[data-symbol] { text-decoration: none; color: currentColor; background-color: transparent }
[data-symbol]>.header {
padding: .25rem .5rem; text-align: center; border-radius: 50%;
/* responsive sizes: p1(320,50) p2(1920,180) */
width : calc(8.125vmin + 24px);
height: calc(8.125vmin + 24px);
/*
responsive fontsize: p1(320,6) p2(1920,20)
Whether this works as expected depends on the minimum browser
fontsize set by the user (content may overflow .header when set >6px)
Tested defaults on W10:
Edge2020 overflows, while Chrome, Firefox and IE11 do not
*/
font-size: calc(.875vmin + 3.2px)
}
[clr="0"] { background-color: Gainsboro; color: black }
.header, /* .header here saves coding html */
[clr="1"] { background-color: #fefefe; color: #1e1e1e }
[clr="2"] { background-color: #1e1e1e; color: Yellow ; font-weight: bolder }
[clr="3"] { background-color: #ffcc01; color: #1e1e1e; font-weight: bolder }
/**************************************/
/* Google Material Component inspired */
/**************************************/
[icon] {
display: inline-flex;
justify-content: center; align-content: center; align-items: center;
/* responsive sizes: p1(320,14) p2(1280,32) */
width : calc(1.875vmin + 8px);
height : calc(1.875vmin + 8px);
line-height: calc(1.875vmin + 8px);
font-size : calc(1.875vmin + 8px);
/*
A bit overdone for just one icon, use inline SVG instead,
or create a small (subset) iconfont at https://icomoon.io
icon list: https://material.io/resources/icons/?style=baseline
*/
font-family: 'Material Icons';
font-weight: normal; font-style: normal; letter-spacing: normal;
text-transform: none; white-space: nowrap; word-wrap: normal;
opacity: 1; /* GMC uses <1 here and 1 on :hover */
-moz-font-feature-settings: 'liga';
font-feature-settings : 'liga';
-moz-osx-font-smoothing : grayscale;
}
/******************/
/* simple banding */
/******************/
[band] { display: flex; flex-flow: row wrap;
justify-content: center; align-content: center;
padding: calc(5vh + 48px) calc(19.5vw - 54.4px) }
/*
responsive padding
T/B: p1(320,64) p2(1920,144) => y = 0.5x + 48
L/R: p1(320, 8) p2(1920,320) => y = 0.195x - 54.4
This construction keeps content nicely center aligned within
given space.
*/
/* [OPTIONAL] */
#media screen and (max-width: 319px) { [band] { padding: 1.5rem 8px } }
#media screen and (min-width:1921px) { [band] { padding: 1.5rem 320px } }
/***********************/
/* Some extra eyecandy */
/***********************/
[data-symbol]>.header {
box-shadow: 0px 2px 1px -1px rgba(0,0,0,.20),
0px 1px 1px 0px rgba(0,0,0,.14),
0px 1px 3px 0px rgba(0,0,0,.12); /* GMC elevation 1dp */
}
[data-symbol]>.header:hover:not(:focus) { transform: scale(1.01) }
[data-symbol]>.header:active:not(:focus) { transform: scale(0.995);
box-shadow: 0px 3px 5px -1px rgba(0,0,0,.2),
0px 5px 8px 0px rgba(0,0,0,.14),
0px 1px 14px 0px rgba(0,0,0,.12); /* GMC elevation 5dp */
}
[data-symbol]>.header:hover {
box-shadow: 0px 3px 5px -1px rgba(0,0,0,.2),
0px 6px 10px 0px rgba(0,0,0,.14),
0px 1px 18px 0px rgba(0,0,0,.12); /* GMC elevation 6dp */
}
/*
ALGEBRA for responsive sizing
ALL responsive sizes in this document use the 'point-slope' variation
of the 'definition of a straight line: y=mx+b':
(https://www.mathsisfun.com/algebra/line-equation-point-slope.html)
y - y1 = y1 + m(x - x1) <=> y = y1 + m(x - x1)
For points:
p1 = (x1,y1) - size at minimum viewport size (x1 default 320px)
p2 = (x2,y2) - size at maximum viewport size (x2 default 1280px)
(using 320px and 1280px will create a full step each 160px)
where:
m = (y2 - y1) / (x2 - x1) ('Slope')
x = fixed value of 100vmin, 100vh or 100vw ('X-intercept')
b = y1 - (m * x1) ('Y-intercept')
X-axis = viewport size
Y-axis = element size
Substituted equation to use:
y = y1 + (y2 - y1) / (x2 - x1) * (x - x1)
NOTES
- Use VMIN for viewport width/height independed results (like fonts)
- Use VW/VH for viewport width/height dependend results (width,height,margin,padding)
- Do not use VMAX for x, it will yield results that are to large.
EXTRA
Helpfull hands-on graphical tool/demo I created on GeoGebra
'ERS linear equations' https://www.geogebra.org/m/gct3bvsp
(E)asy (R)esponsiveness (S)system
*/
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" crossorigin="anonymous">
<body dir="ltr" no-select hover="0" outlines="0">
<section band>
<div data-chart="OC" C>
<div data-knot="branch" C>
<div data-knot="node.step.start">
<div data-symbol>
<div class="header" clr="2"><div><i icon>account_balance</i><br>Group Board</div></div>
</div>
</div>
<div data-knot="node.step">
<div data-symbol>
<div class="header" clr="3"><div><i icon>account_balance</i><br>Board Committees</div></div>
</div>
</div>
</div>
<div data-knot="branch">
<div data-knot="node.lft">
<div data-knot="step">
<div data-symbol>
<div class="header"><div>Audit</div></div>
</div>
</div>
</div>
<div data-knot="node.ctr">
<div data-knot="step">
<div data-symbol>
<div class="header"><div>Remuneration and Human Resources</div></div>
</div>
</div>
</div>
<div data-knot="node.ctr">
<div data-knot="node.step"><!-- empty data-knot for vertical line --></div>
</div>
<div data-knot="node.ctr">
<div data-knot="step">
<div data-symbol>
<div class="header"><div>Social Ethics</div></div>
</div>
</div>
</div>
<div data-knot="node.rgt">
<div data-knot="step">
<div data-symbol>
<div class="header"><div>Nominations</div></div>
</div>
</div>
</div>
</div>
<div data-knot="branch">
<div data-knot="node.lft">
<div data-knot="step">
<div data-symbol>
<div class="header" clr="3"><div><i icon>account_balance</i><br>Compliance Committee</div></div>
</div>
</div>
</div>
<div data-knot="node.ctr">
<div data-knot="node.step"></div>
</div>
<div data-knot="node.rgt">
<div data-knot="step">
<div data-symbol>
<div class="header" clr="3"><div><i icon>account_balance</i><br>Executive Committees</div></div>
</div>
</div>
</div>
</div>
<div data-knot="branch">
<div data-knot="node.lft">
<div data-knot="step">
<div data-symbol>
<div class="header"><div>Group Searching</div></div>
</div>
</div>
</div>
<div data-knot="node.ctr">
<div data-knot="step">
<div data-symbol>
<div class="header"><div>Group Operation</div></div>
</div>
</div>
</div>
<div data-knot="node.ctr">
<div data-knot="node.step.stop">
<div data-symbol>
<div class="header"><div>Group Talent</div></div>
</div>
</div>
</div>
<div data-knot="node.ctr">
<div data-knot="step">
<div data-symbol>
<div class="header"><div>Group Treasure</div></div>
</div>
</div>
</div>
<div data-knot="node.rgt">
<div data-knot="step">
<div data-symbol>
<div class="header"><div>Group Transformation</div></div>
</div>
</div>
</div>
</div>
</div>
</section>
</body>
Remove margin: 0 .2em .5em; padding: 3.7em .5em; from .tree code, .tree span classes.
Also is you want the circle to accurate circles then remove margin and padding from the classes level1 & level2.
CodePen Link: https://codepen.io/manaskhandelwal1/pen/XWbpzMx
.tree,
.tree ul,
.tree li {
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
.tree {
margin: 0 0 1em;
text-align: center;
}
.tree,
.tree ul {
display: table;
}
.tree ul {
width: 100%;
}
.tree li {
display: table-cell;
padding: .5em 0;
vertical-align: top;
}
.tree li:before {
outline: solid 1px #666;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
}
.tree li:first-child:before {
left: 50%;
}
.tree li:last-child:before {
right: 50%;
}
.tree code,
.tree span {
display: inline-block;
position: relative;
height: 150px;
width: 150px;
border-radius: 50%;
background-color: #fefefe;
}
.lineh {
margin-top: -9px !important;
margin-bottom: 0px !important;
border: 0 !important;
border-top: 2px solid !important;
width: 159px;
}
.minus-space {
margin-top: 10px !important;
}
.tree span i {
font-size: 40px
}
.tree span.level1 {
background-color: #1e1e1e;
color: yellow;
}
.tree span.level2 {
background-color: #ffcc01;
}
.tree span.linev {
background-color: #666 !important;
width: 2px !important;
border-radius: 0% !important;
padding: 0px !important;
margin: 0px !important;
}
.tree ul:before,
.tree code:before,
.tree span:before {
outline: solid 1px #666;
content: "";
height: .5em;
left: 50%;
position: absolute;
}
.tree ul:before {
top: -.5em;
}
.tree code:before,
.tree span:before {
top: -.55em;
}
.tree>li {
margin-top: 0;
}
.tree>li:before,
.tree>li:after,
.tree>li>code:before,
.tree>li>span:before {
outline: none;
}
<div class="container-fluid">
<ul class="tree">
<li><span class="level1"><i class="mdi mdi-bank"></i><br><b>Group board</b></span>
<ul>
<li><span class="level2"><i class="mdi mdi-bank"></i><br><b>Board committees</b></span>
<ul>
<li> <span>Audit</span>
</li>
<li> <span>Remuneration and human ressources</span>
</li>
<li> <span class="linev"></span>
<ul>
<li> <span class="level2"><i class="mdi mdi-bank"></i><br><b>Compliance
committees</b></span>
</li>
<li> <span class="linev"></span>
<ul>
<li><span>Group searching</span></li>
<li><span>Group operation</span></li>
<li><span>Strategic talent</span></li>
<li><span>Group treasure</span></li>
<li><span>Group transformation</span></li>
</ul>
</li>
<li> <span class="level2"><i class="mdi mdi-bank"></i><br><b>Executive <br> committees</b></span>
</li>
</ul>
</li>
<li> <span>Social ethics</span>
</li>
<li> <span>Nominations</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>

How does Bootstrap add "/" to breadcrumb components?

Bootstrap breadcrumb components in both v3 and v4 add a "/" to list items:
http://getbootstrap.com/components/#breadcrumbs
https://v4-alpha.getbootstrap.com/components/breadcrumb/
The docs say:
Separators are automatically added in CSS through ::before and
content.
So, I looked at the source code, the relevant section showing:
.breadcrumb-item + .breadcrumb-item::before {
display: inline-block;
padding-right: 0.5rem;
padding-left: 0.5rem;
color: #636c72;
content: "/";
}
However, the content: "/"; only exists on the breadcrumb-item rule. Yet, it seems to work when I follow the v3 docs, which don't require a breadcrumb-item class for items inside a list:
<ol class="breadcrumb">
<li class=''>Home</li>
<li class=''>Library</li>
<li class="active">Data</li>
</ol>
JSFiddle
Why does the above HTML with the above CSS result in / separators being added to items in a .breadcrumb list even though they don't have the .breadcrumb-item class and thus can't benefit from the content: "/" rule? Inspecting the output HTML in JSFiddle shows that no bootstrap javascript magic has added a .breadcrumb-item class to my html list items.
link to this style at github (bootstrap v3.3.7):
https://github.com/twbs/bootstrap/blob/v3.3.7/less/breadcrumbs.less
for (bootstrap v4.0.0):
https://github.com/twbs/bootstrap/blob/v4.0.0-alpha.6/scss/_breadcrumb.scss
(bootstrap v3.3.7 --> breadcrumbs.less)
//
// Breadcrumbs
// --------------------------------------------------
.breadcrumb {
padding: #breadcrumb-padding-vertical #breadcrumb-padding-horizontal;
margin-bottom: #line-height-computed;
list-style: none;
background-color: #breadcrumb-bg;
border-radius: #border-radius-base;
> li {
display: inline-block;
+ li:before {
content: "#{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space
padding: 0 5px;
color: #breadcrumb-color;
}
}
> .active {
color: #breadcrumb-active-color;
}
}
(bootstrap v4.0.0 --> _breadcrumb.scss)
.breadcrumb {
padding: $breadcrumb-padding-y $breadcrumb-padding-x;
margin-bottom: $spacer-y;
list-style: none;
background-color: $breadcrumb-bg;
#include border-radius($border-radius);
#include clearfix;
}
.breadcrumb-item {
float: left;
// The separator between breadcrumbs (by default, a forward-slash: "/")
+ .breadcrumb-item::before {
display: inline-block; // Suppress underlining of the separator in modern browsers
padding-right: $breadcrumb-item-padding;
padding-left: $breadcrumb-item-padding;
color: $breadcrumb-divider-color;
content: "#{$breadcrumb-divider}";
}
// IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built
// without `<ul>`s. The `::before` pseudo-element generates an element
// *within* the .breadcrumb-item and thereby inherits the `text-decoration`.
//
// To trick IE into suppressing the underline, we give the pseudo-element an
// underline and then immediately remove it.
+ .breadcrumb-item:hover::before {
text-decoration: underline;
}
+ .breadcrumb-item:hover::before {
text-decoration: none;
}
&.active {
color: $breadcrumb-active-color;
}
}
In version 3 of Bootstrap, the separators are coming from:
.breadcrumb>li+li:before {
padding: 0 5px;
color: #ccc;
content: "/\00a0";
}
on line 6 of the included file breadcrumbs.less.
Hope this helps! :)
When you inspect the element, you get the style to be:
.breadcrumb > li + li:before {
padding: 0 5px;
color: #ccc;
content: "/\00a0";
}
So the above code targets all the descending <li> elements inside the .breadcrumb element.
The logic is pretty simple. The next element has a breadcrumb before.
There is a CSS rule like this:
.breadcrumb>li+li:before {
padding: 0 5px;
color: #ccc;
content: "/\00a0";
}

Scalable div larger than window

Concept
I'm trying to get a list larger than the window, which will move depending on mouse position. The goal is to allow the user to see all list entries, whatever their amount.
Below is a simple image to illustrate the concept :
Black frame is the window
Black arrow is the mouse position
Red line is the list
Problem
Currently, I can make this work only if I set the list width. I would like to not set this width.
Here's the code:
$(document).ready(function() {
var widthPage = $('.strip').width();
var widthStrip = $('.strip ul').width();
$('.strip').on('mousemove', function(event) {
var offset = $(this).offset();
var relX = event.pageX - offset.left;
var left = relX * (widthStrip - widthPage) / widthPage;
$(this).find('ul').css('left', '-'+left+'px');
});
});
/* Positioning */
.strip {
position:relative;
overflow: hidden;
}
.strip ul {
position: absolute;
top: 0; left: 0;
width: 1750px;
}
.strip li {
display: block;
float: left;
}
/* Style */
body {
padding: 0;
margin: 0;
}
.strip {
height: 30px;
margin-top: 50px;
}
.strip ul {
height: 30px;
padding: 0;
margin: 0;
}
.strip li {
list-style: none;
border: 1px solid #EBEBEB;
margin-right: -1px;
padding: 0 5px;
line-height: 28px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="strip">
<ul>
<li>Lorem</li>
<li>Ipsum</li>
<li>Dolor</li>
<li>Sit</li>
<li>Amet</li>
<li>Consectetur</li>
<li>Adipisicing</li>
<li>Elit</li>
<li>Sed</li>
<li>Do</li>
<li>Eiusmod</li>
<li>Tempor</li>
<li>Incididunt</li>
<li>Ut</li>
<li>Labore</li>
<li>Et</li>
<li>Dolore</li>
<li>Magna</li>
<li>Aliqua</li>
<li>Ut</li>
<li>Enim</li>
<li>Ad</li>
<li>Minim</li>
<li>Veniam</li>
<li>Quis</li>
<li>Nostrud</li>
<li>Exercitation</li>
<li>Ullamco</li>
<li>Laboris</li>
<li>Nisi</li>
<li>Ut</li>
<li>Aliquip</li>
<li>Ex</li>
<li>Ea</li>
<li>Commodo</li>
<li>Consequat</li>
</ul>
</div>
The issue here is that to force the floated elements to expand beyond the page's width, you need to force their container to have a width sufficient to hold them all. I propose using display: inline-block instead, as they will continue so long as their container specifies white-space: nowrap.
.strip {
position:relative;
white-space: nowrap;
overflow: hidden;
}
.strip ul {
position: absolute;
top: 0; left: 0;
font-size: 0; /* prevent html whitespace from displaying */
}
.strip li {
display: inline-block;
font-size: 16px; /* reset font size so the elements appear */
}
After setting these styles, the list will scroll correctly without an explicit width set.
One way to do it would be to make .strip very large and change widthPage to a grandparent's width who's size is equivalent to the original parent's, in this case var widthPage = window.innerWidth;
Demo Here
Changed CSS
body { overflow-x: hidden; }
.strip {
position:relative;
overflow: hidden;
width:10000px; /* Arbitrary large value */
}
.strip ul {
position: absolute;
top: 0; left: 0;
width: auto;
}

Building overlapping, oddly-rotated sprites

My current project involves setting up a bunch of sidebar links, such that the finished design looks like this:
The envelopes are supposed to move and overlap (i.e., change z-index), depending upon which icon/text is currently has :hover state.
I thought each would be a separate PNG file, but I've been given a sprite that looks like this:
Any suggestions how I could achieve this? Normally I'd just change the background position of the list elements each piece of text is in, but I don't think this is possible given the overlapping nature of these. Does he just need to export it differently?
Many thanks...
To me it looks like that sprite would work perfectly. The left most image is for when book is hovered, second image for twitter, third for facebook, forth for email. I'm guessing the last one is just the default state. Its tricky to make this work with pure css and :hover (but possible!), however, it would be extremely easy with javascript.
For the pure css solution, the div with the sprite would have to be the child of all the text elements, so you could change the background based on :hover on the parent (the text). If this isn't clear, I can make you some example code.
Edit:
Its not perfect, but its a proof of concept.
JsFiddle: http://jsfiddle.net/jp6fy/
CSS:
#side{
position:relitive;
height:341px;
width:250px;
}
#link1{
top:0;
}
.link{
position:absolute;
left:0;
top:85px;
height:85px;
padding-left:160px;
width:90px;
}
#image{
position:absolute;
top:-255px;
left:0;
z-index:-1;
background:url(http://i.stack.imgur.com/I2Y4k.png) -720px 0;
height:341px;
width:150px;
}
#link1:hover #image{
background-position:-540px 0;
}
#link2:hover #image{
background-position:-360px 0;
}
#link3:hover #image{
background-position:-180px 0;
}
#link4:hover #image{
background-position:-0px 0;
}
HTML:
<div id='side'>
<div class='link' id='link1'>
email
<div class='link' id='link2'>
facebook
<div class='link' id='link3'>
twitter
<div class='link' id='link4'>
book
<div id='image'></div>
</div>
</div>
</div>
</div>
</div>
It is possible. (But ugly.)
As a :hover selector can only affect elements inside (or directly adjacent) to the triggering element, the solution is to nest the trigger elements: (jsFiddle)
<style>
div {
width: 100px;
height: 100px;
position: absolute;
left: 100px;
}
#image { background: black; }
#trigger1, #trigger1:hover #image { background: red; }
#trigger2, #trigger2:hover #image { background: green; }
#trigger3, #trigger3:hover #image { background: blue; }
</style>
<div id="trigger1">
<div id="trigger2">
<div id="trigger3">
<div id="image"></div>
</div>
</div>
</div>
But preferably, you'd get the envelope sprites exported separately (you can of course still use CSS sprites). That should give you simpler HTML and CSS, a smaller image, and you'll avoid having to muck around with nested absolutely positioned elements, each having its own coordinate system.
I tried an approach which keeps the markup fairly simple, with only one extra non-semantic div per item:
<ul>
<li id="email">
<div class="background"></div>
<em>Email</em> chris
</li>
<li id="facebook">
<div class="background"></div>
<em>Facebook</em> follow us
</li>
<li id="twitter">
<div class="background"></div>
<em>Twitter</em> your life away
</li>
<li id="book">
<div class="background">
</div><em>Book</em> a project
</li>
</ul>
I positioned all the different copies of the background div at the same place, then varied the background position based on the hover states:
/* First, just style the document and the list text in general.
skip on for the important bit */
body {
background-color: black;
color: white;
}
ul {
width: 350px;
margin-top: 40px;
position: relative;
}
li {
margin-right: 40px;
font-family: "Century Gothic", Helvetica, sans-serif;
text-align: right;
margin-bottom: 0px;
padding: 15px 4px 25px 0;
}
li em {
text-transform: uppercase;
display: block;
}
li:hover {
color: red;
}
/* From here down is the important bit */
/* Set up the sprite in all the .background divs */
div.background {
background-image: url(http://i.stack.imgur.com/I2Y4k.png);
position: absolute;
top: 0;
left: 0;
height: 341px;
width: 160px;
}
/* By default, turn off the background in all the divs */
div.background {
display: none;
}
/* Just picking an arbitrary item to show the default, non-hover background */
#email div.background {
display: block;
background-position-x: -737px;
}
/* If we're hovering over the list as a whole, disable the default background,
so it doesn't show up underneath the background we want to display */
ul:hover #email div.background {
display: none;
}
/* For the email item, which shows our arbitrary default background, override
to the email background on hover with more specificity than the default rule */
ul:hover #email:hover div.background {
display: block;
background-position-x: 0px;
}
/* For all other items, override to their background on hover */
#facebook:hover div.background {
display: block;
background-position-x: -375px;
}
#twitter:hover div.background {
display: block;
background-position-x: -189px;
}
#book:hover div.background {
display: block;
background-position-x: -556px;
}
Working, though slightly rough example, in this jsFiddle.
Note that it's okay to have multiple copies of the sprite in multiple different divs; the browser will just grab one copy for its cache and use that for all instances of the image.
Could you create an image map and then hover swaps the image to the one with the correct envelope in front. See this link on an interesting link
google search link on idea
My method with clean HTML.
.nav { position: relative; }
.nav li {
margin-left: 179.8px;
list-style-type: none;
}
.nav li:before {
position: absolute;
left: 0; top: 0;
content: url(http://i.stack.imgur.com/I2Y4k.png);
clip: rect(0 899px 341px 719.2px);
margin-left: -719.2px;
z-index: 1;
}
.nav li:hover:before { z-index: 2; }
.email:hover:before {
clip: rect(0 179.8px 341px 0);
margin-left: 0;
}
.facebook:hover:before {
clip: rect(0 359.6px 341px 179.8px);
margin-left: -179.8px;
}
.twitter:hover:before {
clip: rect(0 539.4px 341px 359.6px);
margin-left: -359.6px;
}
.book:hover:before {
clip: rect(0 719.2px 341px 539.4px);
margin-left: -539.4px;
}
<ul class="nav">
<li class="email">Email</li>
<li class="facebook">Facebook</li>
<li class="twitter">Twitter</li>
<li class="book">Book</li>
</ul>