See modified pens/snippets with text scrolling from bottom:
* {
box-sizing: border-box;
}
@-webkit-keyframes ticker {
0% {
-webkit-transform: translate3d(0, 100%, 0);
/* start off screen, at 100% */
transform: translate3d(0, 100%, 0);
/* same as above */
visibility: visible;
}
100% {
-webkit-transform: translate3d(0, -100%, 0);
/* y instead of x, was: translate3d(-100%, 0, 0) */
transform: translate3d(0, -100%, 0);
/* same as above */
}
}
@keyframes ticker {
0% {
-webkit-transform: translate3d(0, 100%, 0);
/* same as above */
transform: translate3d(0, 100%, 0);
/* same as above */
visibility: visible;
}
100% {
-webkit-transform: translate3d(0, -100%, 0);
/* same as above */
transform: translate3d(0, -100%, 0);
/* same as above */
}
}
.ticker-wrap {
position: fixed;
top: 0;
/* new: align top */
left: 0;
/* instead of bottom: 0; */
height: 100%;
/* instead of width: 100%; */
overflow: hidden;
width: 4rem;
/* instead of height: 4rem; */
background-color: rgba(0, 0, 0, 0.9);
box-sizing: content-box;
}
.ticker-wrap .ticker {
display: inline-block;
width: 4rem;
/* instead of height: 4rem; */
line-height: 4rem;
white-space: nowrap;
box-sizing: content-box;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-webkit-animation-name: ticker;
animation-name: ticker;
-webkit-animation-duration: 30s;
animation-duration: 30s;
}
.ticker-wrap .ticker .ticker__item {
display: inline-block;
padding: 0;
/* or, if you want a gap between text disappearing and appearing again: */
/* padding: 2rem 0; */
/* instead of 0 2rem; */
font-size: 2rem;
color: white;
/* for text rotation: */
writing-mode: vertical-lr;
/* or vertical-rl, doesn't matter if you have one line */
/* from https://stackoverflow.com/a/50171747/15452072 */
}
body {
padding-left: 5rem;
}
/*h1,
h2,
p {
padding: 0 5%;
}*/
<h1>Pure CSS Ticker (No-JS)</h1>
<h2>A smooth horizontal news like ticker using CSS transform on infinite loop</h2>
<div class="ticker-wrap">
<div class="ticker">
<!-- more than one item do not show anyway, no idea why they were there -->
<div class="ticker__item">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
</div>
</div>
<p>So, annoyingly, most JS solutions don't do horizontal tickers on an infinite loop, nor do they render all that smoothly.</p>
<p>The difficulty with CSS was getting the animation to transform the entire items 100% yet include an offset that was only the width of the browser (and not the items full width).</p>
<p>Setting the start of the animation to anything less than zero (e.g. -100%) is unreliable as it is based on the items width, and may not offset the full width of the browser or creates too large an offset</p>
<p>Padding left on the wrapper allows us the correct initial offset, but you still get a 'jump' as it then loops too soon. (The full text does not travel off-screen)</p>
<p>This is where adding display:inline-block to the item parent, where the natural behaviour of the element exists as inline, gives an opportunity to add padding-right 100% here. The padding is taken from the parent (as its treated as inline) which usefully is the wrapper width.</p>
<p><b>Magically*</b> we now have perfect 100% offset, a true 100% translate (width of items) and enough padding in the element to ensure all items leave the screen before it repeats! (width of browser)</p>
<p>*Why this works: The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box. <br>Uses `box-sizing: content-box`<br>
Padding is calculated on the width of the containing box.<br>
So as both the ticker and the items are formatted as nested inline, the padding must be calculated by the ticker wrap.</p>
<p>Ticker content c/o <a href="http://hipsum.co/">Hipsum.co</a></p>
or with text scrolling from top
* {
box-sizing: border-box;
}
@-webkit-keyframes ticker {
/* additionaly, here we change the order of keyframes */
0% {
-webkit-transform: translate3d(0, -100%, 0);
/* y instead of x, was: translate3d(-100%, 0, 0) */
transform: translate3d(0, -100%, 0);
/* same as above */
}
100% {
-webkit-transform: translate3d(0, 100%, 0);
/* start off screen, at 100% */
transform: translate3d(0, 100%, 0);
/* same as above */
visibility: visible;
}
}
@keyframes ticker { /* same as above */
0% {
-webkit-transform: translate3d(0, -100%, 0);
/* same as above */
transform: translate3d(0, -100%, 0);
/* same as above */
}
100% {
-webkit-transform: translate3d(0, 100%, 0);
/* same as above */
transform: translate3d(0, 100%, 0);
/* same as above */
visibility: visible;
}
}
.ticker-wrap {
position: fixed;
top: 0;
/* new: align top */
left: 0;
/* instead of bottom: 0; */
height: 100%;
/* instead of width: 100%; */
overflow: hidden;
width: 4rem;
/* instead of height: 4rem; */
background-color: rgba(0, 0, 0, 0.9);
box-sizing: content-box;
}
.ticker-wrap .ticker {
display: inline-block;
width: 4rem;
/* instead of height: 4rem; */
line-height: 4rem;
white-space: nowrap;
box-sizing: content-box;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-webkit-animation-name: ticker;
animation-name: ticker;
-webkit-animation-duration: 30s;
animation-duration: 30s;
}
.ticker-wrap .ticker .ticker__item {
display: inline-block;
padding: 0;
/* or, if you want a gap between text disappearing and appearing again: */
/* padding: 2rem 0; */
/* instead of 0 2rem; */
font-size: 2rem;
color: white;
/* for text rotation: */
writing-mode: vertical-lr;
/* or vertical-rl, doesn't matter if you have one line */
/* from https://stackoverflow.com/a/50171747/15452072 */
/* and we want it the other way, from top to bottom, so we need to rotate: */
-webkit-transform: rotate(-180deg);
-moz-transform: rotate(-180deg);
transform: rotate(-180deg);
/* filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); */
/* do not bother supporting IE, it's dead */
}
body {
padding-left: 5rem;
}
/*h1,
h2,
p {
padding: 0 5%;
}*/
<h1>Pure CSS Ticker (No-JS)</h1>
<h2>A smooth horizontal news like ticker using CSS transform on infinite loop</h2>
<div class="ticker-wrap">
<div class="ticker">
<!-- more than one item do not show anyway, no idea why they were there -->
<div class="ticker__item">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>
</div>
</div>
<p>So, annoyingly, most JS solutions don't do horizontal tickers on an infinite loop, nor do they render all that smoothly.</p>
<p>The difficulty with CSS was getting the animation to transform the entire items 100% yet include an offset that was only the width of the browser (and not the items full width).</p>
<p>Setting the start of the animation to anything less than zero (e.g. -100%) is unreliable as it is based on the items width, and may not offset the full width of the browser or creates too large an offset</p>
<p>Padding left on the wrapper allows us the correct initial offset, but you still get a 'jump' as it then loops too soon. (The full text does not travel off-screen)</p>
<p>This is where adding display:inline-block to the item parent, where the natural behaviour of the element exists as inline, gives an opportunity to add padding-right 100% here. The padding is taken from the parent (as its treated as inline) which usefully is the wrapper width.</p>
<p><b>Magically*</b> we now have perfect 100% offset, a true 100% translate (width of items) and enough padding in the element to ensure all items leave the screen before it repeats! (width of browser)</p>
<p>*Why this works: The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box. <br>Uses `box-sizing: content-box`<br>
Padding is calculated on the width of the containing box.<br>
So as both the ticker and the items are formatted as nested inline, the padding must be calculated by the ticker wrap.</p>
<p>Ticker content c/o <a href="http://hipsum.co/">Hipsum.co</a></p>
Explanation of changes is in css comments