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;
}
Related
Hello everybody I just started learning HTML and CSS to make my own page from scratch so, for this thread I just need some assistance with the social media bar, essentially what I need is just to make the bar capable of zooming in and out following the mouse wheel scroll of user, meaning that I won't have situations like this:
It should look like this instead (edited on paint):
here it's the code:
html:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Community Impact</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css">
<link href="community-impactstyle.css" rel="stylesheet">
</head>
<body>
<div class="s">
Return to Index<i class="fas fa-hand-point-left"></i>
</div>
<h3>Noah Verner</h3>
<header>
</header>
<main>
<article>
</article>
<aside>
</aside>
</main>
<footer>Made by NOAH VERNER</footer>
</body>
</html>
css:
#font-face{
src: url(Fonts/InputSerifCondensed-Regular.ttf);
font-family: InputSerif;
}
*{
font-family: InputSerif ;
}
body{
background-color: #F5DC00;
margin: 0;
padding: 0;
color: #000000;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
h3 {
position: fixed;
top: -20px ;
left: 0;
right: 0;
font-size: 12px;
background-color: black;
color: white;
font-size: 20px;
text-align: center;
}
footer{
position: fixed;
left: 0;
bottom: 0;
width: 100%;
background-color: black;
color: white;
font-weight: bold;
text-align: center;
}
/*Barra de iconos de redes sociales*/
.s{
position: absolute;
justify-content: center;
height: 100vh;
display: flex;
flex-direction: column;
transform: translate(-1070px,0px);
}
.s a{
color: #F5DC00;
background: rgba(0, 0, 0, 1);
font-size: 20px;
font-weight: 600;
text-decoration: none;
display: block;
margin: 5px;
padding: 20px;
width: 300px;
text-align: right;
border-radius: 50px;
transition: 1s;
transition-property: transform;
}
.s a:hover{
transform: translate(200px, 0);
}
.s i{
margin-left: 10px;
font-size: 30px;
width: 30px;
height: 30px;
}
.s a:nth-child(1) i{
color: #F5DC00;
}
I know the code above doesn't contain all the 5 buttons, but I guess the solution could be applied to the "s" class rather than each button individually, and I tend to think the solution would be applied to the css file, but I'm a noob atm and can't figure it out
any ideas?
You're issue is that you are using the transform property to shift your element out of frame. A more robust way to do this would be to use the left property.
While we probably could find a way to do this in CSS, a more accurate way to do it would be using a touch of JavaScript - like so:
//get all of our social tabs as an array
let socialElem = document.querySelectorAll('.social');
//loop through the array
socialElem.forEach((elem) => {
//define our text element within the tab
let text = elem.querySelector('.hidden');
//get it's dimensions as a JavaScript object
let textSize = text.getBoundingClientRect();
/* now, using the dimensions object above, we can return the 'right' pixel value
of our text element. If we scoot our tab in by the negative of that number it should
perfectly hide our text without using transform.*/
elem.style.left = -textSize.right + 'px';
//we also add 'px' so that CSS can read it
})
:root {
/* set an accent color variable to make my life easier */
--col-acc: #F5DC00;
}
body {
/* reset default body styles */
margin: 0;
height: 100vh;
/* set the background color of the body to the accent color variable */
background-color: var(--col-acc);
/* set the font to something more appealing */
font-family: "Segoe UI Variable Text", system-ui, ui-rounded, sans-serif;
}
.social {
/* set the background color of the social tab to black */
background-color: black;
/* set the text color to our accent color variable */
color: var(--col-acc);
/* resize the tab to be the size of it's content */
width: max-content;
/* round the right side */
border-radius: 0 32px 32px 0;
/* fix the tab (absolute would also work here if you don't care about it staying put when scrolling up and down on the page) */
position: fixed;
/* center it vertically (could be applied to a parent/containter for multiple tabs) */
top: 50%;
/* set it to the left side of the screen */
left: 0;
/* center it just a little more vertically */
transform: translateY(-50%);
/* set the transition to the left property with a durration of 0.5 seconds */
transition: left 0.5s;
}
.social a {
/* give the anchor tag a display of block so we can resize it */
display: block;
/* override the color with our accent color*/
color: var(--col-acc);
/* remove the underline */
text-decoration: none;
/* beef up the font a little */
font-weight: 500;
/* make the font bigger */
font-size: 2rem;
/* add some padding to our tab */
padding: 8px 24px;
}
.social:hover, .social:focus-within {
/* on hover (or focus for accesability) set the left position to 0
I set this property to "important" becase the JavaScript is setting the right value to 0
in the elment styles (which normally overrides the stylesheet), so the important here
re-overrides the elment style, if that makes sense*/
left: 0 !important;
}
<div class="social">
<a href="#">
<span class="hidden">Social</span> 🧔
</a>
</div>
You could do a scroll effect where you take the scrollY and sum it with the boundingClientRect position of the element left and then add some constraints for the unit length in pixels within conditionals. Track the up and down scroll direction and add those to the conditionals for the in and out slide of the social icon and containing text.
const socials = document.querySelectorAll('.socials')
let lastScroll = 0;
window.addEventListener('scroll', function(e) {
let value = window.scrollY
let output = ''
let currentScroll = document.documentElement.scrollTop || document.body.scrollTop;
if (currentScroll > 0 && lastScroll <= currentScroll) {
lastScroll = currentScroll
output = "down"
} else {
lastScroll = currentScroll
output = "up"
}
socials.forEach(icon => {
let rect = icon.getBoundingClientRect()
rect.left < -16 && output === "down" ?
icon.style.left = `${rect.left + value * 0.15}px` :
rect.left > -16 && output === "down" ?
icon.style.left = `0px` :
rect.left > "-192" && output === "up" ?
icon.style.left = `${rect.left - value * 0.15}px` :
rect.left < "-192" && output === "up" ?
icon.style.left = `-192px` : null
})
})
body * {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: sans-serif;
}
#container {
height: 300vh;
position: relative;
}
img {
width: 2rem;
height: 2rem;
}
.socials {
display: flex;
justify-content: space-between;
align-items: center;
width: 15rem;
height: auto;
background: green;
color: limegreen;
border-top-right-radius: 2rem;
border-bottom-right-radius: 2rem;
padding: .5rem;
position: fixed;
top: 2rem;
left: -12rem;
}
<div id="container">
<div class="socials">
Follow me on Rumble
<img src="https://img.utdstc.com/icon/01c/903/01c9032ef30ddf7a9f0346ce3a77b92fd5602e34818f25603962012d2792fab6:200">
</div>
</div>
Everybody, I just found out another solution for my issue, which is even more simple and easy (thanks #calvin-bonner for making me realize it):
In my CSS file: I just typed this:
.s{
position: absolute;
justify-content: center;
height: 100vh;
display: flex;
left: 0;
flex-direction: column;
transform: translate(-82.5%);
}
AS you can see, I only added left: 0; and changed transform: translate(-1070px,0px); to transform: translate(-82.5%);, and now it works pretty well just as I expected
(Actual screenshot of my index after applying my simple solution above)
Note: I think this solution works well because I'm not using nor
planning to add a scroll bar on my website
Guys I am a total newbie. I learn through trying to solve problems which I create. I was reading about swaping one sentence and I decided to make this sentences swaped one after another and I failed so far. If original and a new sentence have same length it is easy. But lets assume they are different and need sometimes to go to another row to look like a traditional text. I can't solve it from several hours, in the attached screen there is a results and what I want. I was checking several websites and ideas. I managed to improve how it is showed on a screen, so it is more continuos but still it is not filling blank spaces or doesnt expand if the text is longer. I want after pressing a sentence, replaced it by another but text being continous without any kind of breaks. I based on this website https://css-tricks.com/swapping-out-text-five-different-ways/. Below is my html and css code.
Here is a drawing of my problem - https://ibb.co/qkqMbwB
<html>
<head>
<meta charset="utf-8"/>
<title>IGE</title>
<link rel="stylesheet" href="3code.css">
</head>
<body>
<div class="flexbox-container">
<input type="checkbox" id="zdanie1Checkbox" />
<label id="zdanie1" for="zdanie1Checkbox">Origxt1.</label>
<input type="checkbox" id="zdanie2Checkbox"/>
<label id="zdanie2" for="zdanie2Checkbox"> Original texsdsdsdsdsdsdsdsdddddd sdsd sdsdsdsd sd sd sdt2.</label>
<input type="checkbox" id="zdanie3Checkbox" />
<label id="zdanie3" for="zdanie3Checkbox">Original tsd ext3.</label>
<input type="checkbox" id="zdanie4Checkbox" />
<label id="zdanie4" for="zdanie4Checkbox">Orig sdsdsddsinalText4.</label>
<input type="checkbox" id="zdanie5Checkbox" />
<label id="zdanie5" for="zdanie5Checkbox">Orixt54.</label>
</div>
</body>
</html>
and here is css
body {
padding: 0px 10px 10px 10px;
}
.flexbox-container {
display:flex;
flex-wrap:wrap;
flex-direction: row;
justify-content:flex-start;
align-content:center;
}
#zdanie1 {
position: relative;
}
#zdanie1Checkbox {
display: none;
}
#zdanie1Checkbox:checked + #zdanie1:after {
content: "The outer layer is nearly melted through.";
align-self: stretch;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
color: red;
width:auto!important; /*this set the height to auto for those supporting it (not IE)*/
width:500px; /*for IE, all others override it by the previous rule*/
min-width:500px; /*for the ones that support it (all but IE)*/
padding-right: auto;
}
#zdanie2 {
position: relative;
}
#zdanie2Checkbox {
display: none;
}
#zdanie2Checkbox:checked + #zdanie2:after {
content: "The outer layer is nearly melted through.";
align-self: stretch;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
color: red;
width:auto!important; /*this set the height to auto for those supporting it (not IE)*/
width:500px; /*for IE, all others override it by the previous rule*/
min-width:500px; /*for the ones that support it (all but IE)*/
}
#zdanie3 {
position: relative;
}
#zdanie3Checkbox {
display: none;
}
#zdanie3Checkbox:checked + #zdanie3:after {
content: "Soon the second layer will go.";
align-self: stretch;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
color: red;
width:auto!important; /*this set the height to auto for those supporting it (not IE)*/
width:500px; /*for IE, all others override it by the previous rule*/
min-width:500px; /*for the ones that support it (all but IE)*/
}
#zdanie4 {
position: relative;
}
#zdanie4Checkbox {
display: none;
}
#zdanie4Checkbox:checked + #zdanie4:after {
content: "Then the scanner blinks silver and I’ve got what I came for.";
position: absolute;
align-self: stretch;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
color: red;
overflow-wrap: break-word;
width:auto!important; /*this set the height to auto for those supporting it (not IE)*/
width:500px; /*for IE, all others override it by the previous rule*/
min-width:500px; /*for the ones that support it (all but IE)*/
/* Non standard for webkit */
word-break: break-word;
-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
}
#zdanie5 {
position: relative;
}
#zdanie5Checkbox {
display: none;
}
#zdanie5Checkbox:checked + #zdanie5:after {
content: "The outer layer is nearly melted throu I almost didn’t notice.";
position: absolute;
align-self: stretch;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: white;
color: red;
width:auto!important; /*this set the height to auto for those supporting it (not IE)*/
width:500px; /*for IE, all others override it by the previous rule*/
min-width:500px; /*for the ones that support it (all but IE)*/
}
There many ways to achieve it. The easiest way with the most varity to use would be the use of JS with an onlick event as shown below. In this case you have 2 lines used as a span so that they could be used within a paragraph. One is set to display: none; by default and therefor invisible. With clicking on the line, you trigger the script, that will hide the line with display: none; and show the other by changing it to display: block;.
function show1b() {
document.getElementById("line-1b").style.display = "block";
document.getElementById("line-1a").style.display = "none";
}
function show1a() {
document.getElementById("line-1a").style.display = "block";
document.getElementById("line-1b").style.display = "none";
}
#line-1b {
display: none;
}
<span id="line-1a" onclick="show1b()">This is the original text. Click on me to show the alternative text.</span>
<span id="line-1b" onclick="show1a()">This is the alternative text. Click on me to show the original text.</span>
CSS only
here you "mis-use" the input as a checkbox with the label. You hide the checkbox by using its id and display: none;. then you sue the id of the label with :after to use the attribute content:. Then you define the etxt that should be used. If the checkbox id is checked, then it will dispaly an alternative text as used in the sampel below.
#line-1a {
display: none;
}
#line-1b:after {
content: "This is the original text. Click on me to show the alternative text.";
}
#line-1a:checked + #line-1b:after {
content: "This is the alternative text. Click on me to show the original text.";
}
<input id="line-1a" type="checkbox">
<label for="line-1a" id="line-1b"></label>
A tool-tip is shown when I click inside of a text-box and the tool-tip disappears when I exit the text-box using the following JavaScript codes and CSS. The problem is the scrolling of the page. The position of tool-tip changes equal to the scrolling value. How can I fix the the position of a tool-tip relative to text-box in HTML?
<style type="text/css">
.tooltip {
visibility: hidden;
position: fixed;
width: 450px;
top: 0;
left: 0;
z-index: 2;
color: red;
background-color: #ffffe6;
font-family: 'B Yekan';
font-size: 20px;
text-align: center;
padding: 1px;
border: solid 1px;
border-radius: 5px;
overflow:auto;
}
</style>
<script type="text/javascript">
function tooltip_show(tooltipId, inputId) {
var inputField = document.getElementById(inputId);
var rectObject = inputField.getBoundingClientRect();
var top = rectObject.top, left = rectObject.left;
var it = document.getElementById(tooltipId);
it.style.left = (left - it.offsetWidth / 2 + inputField.offsetWidth / 2) + 'px';
it.style.top = (top + inputField.offsetHeight + 5) + 'px';
var a = inputField.scrollTop;
it.style.visibility = 'visible';
}
function tooltip_hide(tooltipId) {
var it = document.getElementById(tooltipId);
it.style.visibility = 'hidden';
}
</script>
This tooltip created with pure css.
body {
height:800px;
}
.container {
position: relative;
margin-top: 50px;
}
.tooltip {
display: none;
background-color: #000;
position: absolute;
padding: 2px 5px;
border-radius: 10px;
color: orange;
top: -30px;
left: 60px;
}
.tooltip:before {
content: '\25bc';
position: absolute;
top: 18px;
color: #000;
}
.txt:focus + .tooltip {
display: inline-block;
}
<div class="container">
TextBox : <input type="text" class="txt">
<div class="tooltip">This is TextBox</div>
</div>
Please use position absolute instead of fixed.
Apart from the above, be careful with your solution, because if you change the coordinates of the textbox itself, the tooltip will not move together.
A better solution would be to create a wrapper element, make it position relative, and use position absolute on the tooltip. This way, if you move the wrapper around, the tooltip will move with it.
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.
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>