79772046

Date: 2025-09-22 21:01:46
Score: 2
Natty:
Report link

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

Reasons:
  • Blacklisted phrase (1): stackoverflow
  • Probably link only (1):
  • Contains signature (1):
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (0.5):
Posted by: rajniszp