{"id":357,"date":"2024-04-02T12:00:00","date_gmt":"2024-04-02T12:00:00","guid":{"rendered":"http:\/\/sobre-portugal.com\/?p=357"},"modified":"2024-06-12T20:24:55","modified_gmt":"2024-06-12T20:24:55","slug":"infinite-scrolling-logos-in-flat-html-and-pure-css","status":"publish","type":"post","link":"http:\/\/sobre-portugal.com\/index.php\/2024\/04\/02\/infinite-scrolling-logos-in-flat-html-and-pure-css\/","title":{"rendered":"Infinite-Scrolling Logos In Flat HTML And Pure CSS"},"content":{"rendered":"

Infinite-Scrolling Logos In Flat HTML And Pure CSS<\/title><\/p>\n<article>\n<header>\n<h1>Infinite-Scrolling Logos In Flat HTML And Pure CSS<\/h1>\n<address>Silvestar Bistrovi\u0107<\/address>\n<p> 2024-04-02T12:00:00+00:00<br \/>\n 2024-06-12T20:05:40+00:00<br \/>\n <\/header>\n<p>When I was asked to make an auto-scrolling logo farm, I had to ask myself: \u201cYou mean, like a <code><marquee><\/code>?\u201d It\u2019s not the weirdest request, but the thought of a <code><marquee><\/code> conjures up the \u201cold\u201d web days when Geocities ruled. What was next, a repeating sparkling unicorn GIF background?<\/p>\n<p>If you\u2019re tempted to reach for the <code><marquee><\/code> element, don\u2019t. <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Element\/marquee\">MDN has a stern warning about it right at the top of the page<\/a>:<\/p>\n<blockquote><p>\u201c<strong>Deprecated:<\/strong> This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible [\u2026] Be aware that this feature may cease to work at any time.\u201d<\/p><\/blockquote>\n<p>That\u2019s fine because whatever infinite scrolling feature <code><marquee><\/code> is offered, we can most certainly pull off in CSS. But when I researched examples to help guide me, I was surprised to find very little on it. Maybe auto-scrolling elements aren\u2019t the rage these days. Perhaps the sheer nature of auto-scrolling behavior is enough of an accessibility red flag to scare us off.<\/p>\n<p>Whatever the case, we have the tools to do this, and I wanted to share how I went about it. This is one of those things that can be done in lots of different ways, leveraging lots of different CSS features. Even though I am not going to exhaustively explore all of them, I think it\u2019s neat to see someone else\u2019s thought process, and that\u2019s what you\u2019re going to get from me in this article.<\/p>\n<h2 id=\"what-we-re-making\">What We\u2019re Making<\/h2>\n<p>But first, here’s an example of the finished result:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"YzMQMXe\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [CSS only marquee without HTML duplication [forked]](https:\/\/codepen.io\/smashingmag\/pen\/YzMQMXe) by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/YzMQMXe\">CSS only marquee without HTML duplication [forked]<\/a> by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/figcaption><\/figure>\n<p>The idea is fairly straightforward. We want some sort of container, and in it, we want a series of images that infinitely scroll without end. In other words, as the last image slides in, we want the first image in the series to directly follow it in an infinite loop.<\/p>\n<p>So, here\u2019s the plan: <strong>We\u2019ll set up the HTML first, then pick at the container and make sure the images are correctly positioned in it before we move on to writing the CSS animation that pulls it all together.<\/strong><\/p>\n<div data-audience=\"non-subscriber\" data-remove=\"true\" class=\"feature-panel-container\">\n<aside class=\"feature-panel\">\n<div class=\"feature-panel-left-col\">\n<div class=\"feature-panel-description\">\n<p>Meet <strong><a data-instant href=\"https:\/\/www.smashingconf.com\/online-workshops\/\">Smashing Workshops<\/a><\/strong> on <strong>front-end, design & UX<\/strong>, with practical takeaways, live sessions, <strong>video recordings<\/strong> and a friendly Q&A. With Brad Frost, St\u00e9ph Walter and <a href=\"https:\/\/smashingconf.com\/online-workshops\/workshops\">so many others<\/a>.<\/p>\n<p><a data-instant href=\"smashing-workshops\" class=\"btn btn--green btn--large\">Jump to the workshops \u21ac<\/a><\/div>\n<\/div>\n<div class=\"feature-panel-right-col\"><a data-instant href=\"smashing-workshops\" class=\"feature-panel-image-link\"><\/p>\n<div class=\"feature-panel-image\">\n<img decoding=\"async\" loading=\"lazy\" class=\"feature-panel-image-img\" src=\"\/images\/smashing-cat\/cat-scubadiving-panel.svg\" alt=\"Feature Panel\" width=\"257\" height=\"355\" \/><\/p>\n<\/div>\n<p><\/a>\n<\/div>\n<\/aside>\n<\/div>\n<h2 id=\"existing-examples\">Existing Examples<\/h2>\n<p>Like I mentioned, I tried searching for some ideas. While I didn\u2019t find exactly what I was looking for, I did find a few demos that provided a spark of inspiration. What I really wanted was to use CSS only while not having to \u201cclone\u201d the marquee items.<\/p>\n<p>Geoff Graham\u2019s \u201c<a href=\"https:\/\/css-tricks.com\/creating-a-css-sliding-background-effect\/\">Sliding Background Effect<\/a>\u201d is close to what I wanted. While it is dated, it did help me see how I could intentionally use <code>overflow<\/code> to allow images to \u201cslide\u201d out of the container and an animation that loops forever. It\u2019s a background image, though, and relies on super-specific numeric values that make it tough to repurpose in other projects.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"LYvLvGz\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Untitled [forked]](https:\/\/codepen.io\/smashingmag\/pen\/LYvLvGz) by <a href=\"https:\/\/codepen.io\/team\/css-tricks\">@css-tricks<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/LYvLvGz\">Untitled [forked]<\/a> by <a href=\"https:\/\/codepen.io\/team\/css-tricks\">@css-tricks<\/a>.<\/figcaption><\/figure>\n<p>There\u2019s another great example from <a href=\"https:\/\/codepen.io\/Coding_Journey\">Coding Journey<\/a> over at CodePen:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"yLrXrVY\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Marquee-like Content Scrolling [forked]](https:\/\/codepen.io\/smashingmag\/pen\/yLrXrVY) by <a href=\"https:\/\/codepen.io\/Coding_Journey\">Coding Journey<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/yLrXrVY\">Marquee-like Content Scrolling [forked]<\/a> by <a href=\"https:\/\/codepen.io\/Coding_Journey\">Coding Journey<\/a>.<\/figcaption><\/figure>\n<p>The effect is what I\u2019m after for sure, but it uses some JavaScript, and even though it\u2019s just a light sprinkle, I would prefer to leave JavaScript out of the mix.<\/p>\n<p>Ryan Mulligan\u2019s \u201c<a href=\"https:\/\/codepen.io\/hexagoncircle\/pen\/wvmjomb?editors=1000\">CSS Marquee Logo Wall<\/a>\u201d is the closest thing. Not only is it a logo farm with individual images, but it demonstrates how CSS masking can be used to hide the images as they slide in and out of the container. I was able to integrate that same idea into my work.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"ExJXJZm\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [CSS Marquee Logo Wall [forked]](https:\/\/codepen.io\/smashingmag\/pen\/ExJXJZm) by <a href=\"https:\/\/codepen.io\/hexagoncircle\">Ryan Mulligan<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/ExJXJZm\">CSS Marquee Logo Wall [forked]<\/a> by <a href=\"https:\/\/codepen.io\/hexagoncircle\">Ryan Mulligan<\/a>.<\/figcaption><\/figure>\n<p>But there\u2019s still something else I\u2019m after. What I would like is the smallest amount of HTML possible, namely markup that does not need to be duplicated to create the impression that there\u2019s an unending number of images. In other words, we should be able to create an infinite-scrolling series of images where the images are the only child elements in the \u201cmarquee\u201d container.<\/p>\n<p>I did find a few more examples in other places, but these were enough to point me in the right direction. Follow along with me.<\/p>\n<h2 id=\"the-html\">The HTML<\/h2>\n<p>Let’s set up the HTML structure first before anything else. Again, I want this to be as \u201csimple\u201d as possible, meaning very few elements with the shortest family tree possible. We can get by with nothing but the \u201cmarquee\u201d container and the logo images in it.<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-html\"><figure class=\"marquee\">\n <img class=\"marquee__item\" src=\"logo-1.png\" width=\"100\" height=\"100\" alt=\"Company 1\">\n <img class=\"marquee__item\" src=\"logo-2.png\" width=\"100\" height=\"100\" alt=\"Company 2\">\n <img class=\"marquee__item\" src=\"logo-3.png\" width=\"100\" height=\"100\" alt=\"Company 3\">\n<\/figure>\n<\/code><\/pre>\n<\/div>\n<p>This keeps things as \u201cflat\u201d as possible. There shouldn\u2019t be anything else we need in here to make things work.<\/p>\n<h2 id=\"setting-up-the-container\">Setting Up The Container<\/h2>\n<p>Flexbox might be the simplest approach for establishing a row of images with a gap between them. We don\u2019t even need to tell it to flow in a row direction because that\u2019s the default.<\/p>\n<pre><code class=\"language-css\">.marquee {\n display: flex;\n}\n<\/code><\/pre>\n<p>I already know that I plan on using absolute positioning on the image elements, so it makes sense to set relative positioning on the container to, you know, <em>contain<\/em> them. And since the images are in an absolute position, they have no reserved height or width dimensions that influence the size of the container. So, we\u2019ll have to declare an explicit <code>block-size<\/code> (the logical equivalent to <code>height<\/code>). We also need a maximum width so we have a boundary for the images to slide in and out of view, so we\u2019ll use <code>max-inline-size<\/code> (the logical equivalent to <code>max-width<\/code>):<\/p>\n<pre><code class=\"language-css\">.marquee {\n --marquee-max-width: 90vw;\n\n display: flex;\n block-size: var(--marquee-item-height);\n max-inline-size: var(--marquee-max-width);\n position: relative;\n}\n<\/code><\/pre>\n<p>Notice I\u2019m using a couple of CSS variables in there: one that defines the marquee\u2019s height based on the height of one of the images (<code>--marquee-item-height<\/code>) and one that defines the marquee\u2019s maximum width (<code>--marquee-max-width<\/code>). We can give the marquee\u2019s maximum width a value now, but we\u2019ll need to formally register and assign a value to the image height, which we will do in a bit. I just like knowing what variables I am planning to work with as I go.<\/p>\n<p>Next up, we want the images to be hidden when they are outside of the container. We\u2019ll set the horizontal overflow accordingly:<\/p>\n<pre><code class=\"language-css\">.marquee {\n --marquee-max-width: 90vw;\n\n display: flex;\n block-size: var(--marquee-item-height);\n max-inline-size: var(--marquee-max-width);\n overflow-x: hidden;\n position: relative;\n}\n<\/code><\/pre>\n<p>And I <em>really<\/em> like the way Ryan Mulligan used a CSS mask. It creates the impression that images are fading in and out of view. So, let\u2019s add that to the mix:<\/p>\n<pre><code class=\"language-css\">.marquee {\n display: flex;\n block-size: var(--marquee-item-height);\n max-inline-size: var(--marquee-max-width);\n overflow-x: hidden;\n position: relative;\n mask-image: linear-gradient(\n to right,\n hsl(0 0% 0% \/ 0),\n hsl(0 0% 0% \/ 1) 20%,\n hsl(0 0% 0% \/ 1) 80%,\n hsl(0 0% 0% \/ 0)\n );\n position: relative;\n}\n<\/code><\/pre>\n<p>Here\u2019s what we have so far:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"LYvjLLG\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [CSS only marquee without HTML duplication, example 0 [forked]](https:\/\/codepen.io\/smashingmag\/pen\/LYvjLLG) by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/LYvjLLG\">CSS only marquee without HTML duplication, example 0 [forked]<\/a> by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/figcaption><\/figure>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"positioning-the-marquee-items\">Positioning The Marquee Items<\/h2>\n<p>Absolute positioning is what allows us to yank the images out of the document flow and manually position them so we can start there.<\/p>\n<pre><code class=\"language-css\">.marquee__item {\n position: absolute;\n}\n<\/code><\/pre>\n<p>That makes it look like the images are completely gone. But they\u2019re there \u2014 the images are stacked directly on top of one another.<\/p>\n<p>Remember that CSS variable for our container, <code>--marquee-item-height<\/code>? Now, we can use it to match the marquee item height:<\/p>\n<pre><code class=\"language-css\">.marquee__item {\n position: absolute;\n inset-inline-start: var(--marquee-item-offset);\n}\n<\/code><\/pre>\n<p>To push marquee images outside the container, we need to define a <code>--marquee-item-offset<\/code>, but that calculation is not trivial, so we will learn how to do it in the next section. We know what the <code>animation<\/code> needs to be: something that moves linearly for a certain duration after an initial delay, then goes on infinitely. Let\u2019s plug that in with some variables as temporary placeholders.<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">.marquee__item {\n position: absolute;\n inset-inline-start: var(--marquee-item-offset);\n animation: go linear var(--marquee-duration) var(--marquee-delay, 0s) infinite;\n}\n<\/code><\/pre>\n<\/div>\n<p>To animate the marquee items infinitely, we have to define two CSS variables, one for the duration (<code>--marquee-duration<\/code>) and one for the delay (<code>--marquee-delay<\/code>). The duration can be any length you want, but the delay should be calculated, which is what we will figure out in the next section.<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">.marquee__item {\n position: absolute;\n inset-inline-start: var(--marquee-item-offset);\n animation: go linear var(--marquee-duration) var(--marquee-delay, 0s) infinite;\n transform: translateX(-50%);\n}\n<\/code><\/pre>\n<\/div>\n<p>Finally, we will translate the marquee item by <code>-50%<\/code> horizontally. This small \u201chack\u201d handles situations when the image sizes are uneven.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"ExJXJMQ\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [CSS only marquee without HTML duplication, example 2 [forked]](https:\/\/codepen.io\/smashingmag\/pen\/ExJXJMQ) by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/ExJXJMQ\">CSS only marquee without HTML duplication, example 2 [forked]<\/a> by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/figcaption><\/figure>\n<h2 id=\"animating-the-images\">Animating The Images<\/h2>\n<p>To make the animation work, we need the following information:<\/p>\n<ul>\n<li>Width of the logos,<\/li>\n<li>Height of the logos,<\/li>\n<li>Number of items, and<\/li>\n<li>Duration of the animation.<\/li>\n<\/ul>\n<p>Let\u2019s use the following configurations for our set of variables:<\/p>\n<pre><code class=\"language-css\">.marquee--8 {\n --marquee-item-width: 100px;\n --marquee-item-height: 100px;\n --marquee-duration: 36s;\n --marquee-items: 8;\n}\n<\/code><\/pre>\n<p><strong>Note<\/strong>: <em>I\u2019m using the BEM modifier <code>.marquee--8<\/code> to define the animation of the eight logos. We can define the animation keyframes now that we know the <code>--marquee-item-width<\/code> value.<\/em><\/p>\n<pre><code class=\"language-css\">@keyframes go {\n to {\n inset-inline-start: calc(var(--marquee-item-width) * -1);\n }\n}\n<\/code><\/pre>\n<p>The animation moves the marquee item from right to left, allowing each one to enter into view from the right as it travels out of view over on the left edge and outside of the marquee container.<\/p>\n<p>Now, we need to define the <code>--marquee-item-offset<\/code>. We want to push the marquee item all the way to the right side of the marquee container, opposite of the animation end state.<\/p>\n<p>You might think the offset should be <code>100% + var(--marquee-item-width)<\/code>, but that would make the logos overlap on smaller screens. To prevent that, we need to know the minimum width of all logos combined. We do that in the following way:<\/p>\n<pre><code class=\"language-css\">calc(var(--marquee-item-width) * var(--marquee-items))\n<\/code><\/pre>\n<p>But that is not enough. If the marquee container is too big, the logos would take less than the maximum space, and the offset would be within the container, which makes the logos visible inside the marquee container. To prevent that, we will use the <code>max()<\/code> function like the following:<\/p>\n<pre><code class=\"language-css\">--marquee-item-offset: max(\n calc(var(--marquee-item-width) * var(--marquee-items)),\n calc(100% + var(--marquee-item-width))\n);\n<\/code><\/pre>\n<p>The <code>max()<\/code> function checks which of the two values in its arguments is bigger, the overall width of all logos or the maximum width of the container plus the single logo width, which we defined earlier. The latter will be true on bigger screens and the former on smaller screens.<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"BaEZEXN\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [CSS only marquee without HTML duplication, example 3 [forked]](https:\/\/codepen.io\/smashingmag\/pen\/BaEZEXN) by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/BaEZEXN\">CSS only marquee without HTML duplication, example 3 [forked]<\/a> by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/figcaption><\/figure>\n<p>Finally, we will define the complicated animation delay (<code>--marquee-delay<\/code>) with this formula:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">--marquee-delay: calc(var(--marquee-duration) \/ var(--marquee-items) * (var(--marquee-items) - var(--marquee-item-index)) * -1);\n<\/code><\/pre>\n<\/div>\n<p>The delay equals the animation duration divided by a quadratic polynomial (that\u2019s what ChatGPT tells me, at least). The quadratic polynomial is the following part, where we multiply the number of items and number of items minus the current item index:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">var(--marquee-items) * (var(--marquee-items) - var(--marquee-item-index))\n<\/code><\/pre>\n<\/div>\n<p>Note that we are using a negative delay (<code>* -1<\/code>) to make the animation start in the \u201cpast,\u201d so to speak. The only remaining variable to define is the <code>--marquee-item-index<\/code> (the current marquee item position):<\/p>\n<pre><code class=\"language-css\">.marquee--8 .marquee__item:nth-of-type(1) {\n --marquee-item-index: 1;\n}\n.marquee--8 .marquee__item:nth-of-type(2) {\n --marquee-item-index: 2;\n}\n\n\/* etc. *\/\n\n.marquee--8 .marquee__item:nth-of-type(8) {\n --marquee-item-index: 8;\n}\n<\/code><\/pre>\n<p>Here\u2019s that final demo once again:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"xxerNKz\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [CSS only marquee without HTML duplication [forked]](https:\/\/codepen.io\/smashingmag\/pen\/xxerNKz) by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/xxerNKz\">CSS only marquee without HTML duplication [forked]<\/a> by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/figcaption><\/figure>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"motion-sensitivities\">Motion Sensitivities<\/h2>\n<p>While the animation isn’t exactly the most complex and wild thing you’ll find, it still could be a trigger for those with motion sensitivities due to a vestibular disorder. We can slow or eliminate the animation with the <code>prefers-reduced-motion<\/code> media query:<\/p>\n<pre><code class=\"language-css\">@media (prefers-reduced-motion) {\n .marquee__item {\n animation-play-state: paused;\n }\n}\n<\/code><\/pre>\n<p>This does the job, but we could do a little better to make sure more of the logos are visible when the animation is off.<\/p>\n<pre><code class=\"language-css\">@media (prefers-reduced-motion) {\n .marquee {\n justify-content: space-evenly;\n mask-image: unset;\n }\n \n .marquee__item {\n position: unset;\n inset-inline-start: unset;\n transform: unset;\n }\n\n @keyframes go {\n to { \n inset-inline-start: unset;\n }\n }\n}\n<\/code><\/pre>\n<p>A more heavy-handed approach would be to add a button or some other control that toggles between play and pasued states, but whether or not you go that route will depend on your project requirements and whether the animation is essential to your interface.<\/p>\n<h2 id=\"further-improvements\">Further Improvements<\/h2>\n<p>This solution could be better, especially when the logos are not equal widths. To adjust the gaps between inconsistently sized images, we could calculate the delay of the animation more precisely. That is possible because the animation is linear. I\u2019ve tried to find a formula, but I think it needs more fine-tuning, as you can see:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"NWmgVWN\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [CSS only marquee without HTML duplication, example 4 [forked]](https:\/\/codepen.io\/smashingmag\/pen\/NWmgVWN) by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/NWmgVWN\">CSS only marquee without HTML duplication, example 4 [forked]<\/a> by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/figcaption><\/figure>\n<p>Another improvement we can get with a bit of fine-tuning is to prevent big gaps on wide screens. To do that, set the <code>max-inline-size<\/code> and declare <code>margin-inline: auto<\/code> on the <code>.marquee<\/code> container:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"qBwjGBJ\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [CSS only marquee without HTML duplication, example 5 [forked]](https:\/\/codepen.io\/smashingmag\/pen\/qBwjGBJ) by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/qBwjGBJ\">CSS only marquee without HTML duplication, example 5 [forked]<\/a> by <a href=\"https:\/\/codepen.io\/CiTA\">Silvestar Bistrovi\u0107<\/a>.<\/figcaption><\/figure>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>What do you think? Is this something you can see yourself using on a project? Would you approach it differently? I am always happy when I land on something with a clean HTML structure and a pure CSS solution. You can see the final implementation on the <a href=\"https:\/\/heyflow.com\">Heyflow website<\/a>.<\/p>\n<h3 id=\"further-reading-on-smashingmag\">Further Reading On SmashingMag<\/h3>\n<ul>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2022\/03\/designing-better-infinite-scroll\/\">Infinite Scroll UX Done Right: Guidelines and Best Practices<\/a>, Vitaly Friedman<\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2022\/11\/document-object-model-geometry-guide\/\">Document Object Model (DOM) Geometry: A Beginner\u2019s Introduction And Guide<\/a>, Pearl Akpan<\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2020\/03\/infinite-scroll-lazy-image-loading-react\/\">Implementing Infinite Scroll And Image Lazy Loading In React<\/a>, Chidi Orji<\/li>\n<li><a href=\"https:\/\/www.smashingmagazine.com\/2023\/12\/css-scroll-snapping-aligned-global-page-layout-case-study\/\">CSS Scroll Snapping Aligned With Global Page Layout: A Full-Width Slider Case Study<\/a>, Brecht De Ruyte<\/li>\n<\/ul>\n<div class=\"signature\">\n <img decoding=\"async\" src=\"https:\/\/www.smashingmagazine.com\/images\/logo\/logo--red.png\" alt=\"Smashing Editorial\" width=\"35\" height=\"46\" loading=\"lazy\" \/><br \/>\n <span>(gg, yk)<\/span>\n<\/div>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>Infinite-Scrolling Logos In Flat HTML And Pure CSS Infinite-Scrolling Logos In Flat HTML And Pure CSS Silvestar Bistrovi\u0107 2024-04-02T12:00:00+00:00 2024-06-12T20:05:40+00:00 When I was asked to make an auto-scrolling logo farm,<\/p>\n<p class=\"more-link\"><a href=\"http:\/\/sobre-portugal.com\/index.php\/2024\/04\/02\/infinite-scrolling-logos-in-flat-html-and-pure-css\/\" class=\"readmore\">Continue reading<svg class=\"icon icon-arrow-right\" aria-hidden=\"true\" role=\"img\"> <use href=\"#icon-arrow-right\" xlink:href=\"#icon-arrow-right\"><\/use> <\/svg><span class=\"screen-reader-text\">Infinite-Scrolling Logos In Flat HTML And Pure CSS<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-357","post","type-post","status-publish","format-standard","hentry","category-css"],"_links":{"self":[{"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/posts\/357","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/comments?post=357"}],"version-history":[{"count":1,"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/posts\/357\/revisions"}],"predecessor-version":[{"id":358,"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/posts\/357\/revisions\/358"}],"wp:attachment":[{"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/media?parent=357"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/categories?post=357"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/sobre-portugal.com\/index.php\/wp-json\/wp\/v2\/tags?post=357"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}