FreeTrust Builders

Logo Marquee

Seamless infinite scroller for partner / press / customer logos.

#logos#trust#social-proof#marquee#no-js

Live preview

See it in action.

Fully interactive, drag, click, scroll inside the frame, toggle to mobile.

About this section

Pure-CSS infinite logo marquee with grayscale-on-rest, color-on-hover treatment. Zero JS. Speed and direction configurable. Mask-fades the edges for a polished look.

Install in 90 seconds

  1. 01

    Create /sections/modblo-logo-marquee.liquid.

  2. 02

    Paste the code and save.

  3. 03

    Add Logo blocks; the second pass auto-renders for the seamless loop.

The code

This is the file you'll paste into your theme.

modblo-logo-marquee.liquid
{%- comment -%} modblo. Logo Marquee {%- endcomment -%}
<section class="modblo-logos" data-section-id="{{ section.id }}"
  style="--modblo-bg: {{ section.settings.bg }}; --modblo-fg: {{ section.settings.fg }};">
  <div class="modblo-logos__inner page-width">
    {%- if section.settings.heading != blank -%}
      <p class="modblo-logos__heading">{{ section.settings.heading }}</p>
    {%- endif -%}
    <div class="modblo-logos__viewport">
      <div class="modblo-logos__track" aria-hidden="false">
        {%- for block in section.blocks -%}
          <div class="modblo-logos__cell" {{ block.shopify_attributes }}>
            {%- if block.settings.image != blank -%}
              {%- if block.settings.link != blank -%}<a href="{{ block.settings.link }}">{%- endif -%}
              {{ block.settings.image | image_url: width: 240 | image_tag:
                loading: 'lazy', widths: '120,240', alt: block.settings.name, class: 'modblo-logos__img' }}
              {%- if block.settings.link != blank -%}</a>{%- endif -%}
            {%- else -%}
              <span class="modblo-logos__name">{{ block.settings.name }}</span>
            {%- endif -%}
          </div>
        {%- endfor -%}
        {%- comment -%} Duplicate for seamless loop {%- endcomment -%}
        {%- for block in section.blocks -%}
          <div class="modblo-logos__cell" aria-hidden="true">
            {%- if block.settings.image != blank -%}
              {{ block.settings.image | image_url: width: 240 | image_tag: loading: 'lazy', widths: '120,240', alt: '', class: 'modblo-logos__img' }}
            {%- else -%}
              <span class="modblo-logos__name">{{ block.settings.name }}</span>
            {%- endif -%}
          </div>
        {%- endfor -%}
      </div>
    </div>
  </div>
</section>

<style>
  .modblo-logos { background: var(--modblo-bg, #fff); color: var(--modblo-fg, #0b0b0c); padding: clamp(48px,7vw,96px) 0; }
  .modblo-logos__inner { max-width: 1200px; margin: 0 auto; padding: 0 24px; text-align: center; }
  .modblo-logos__heading { font-size: 13px; text-transform: uppercase; letter-spacing: .2em; opacity: .55; font-weight: 600; margin: 0 0 28px; }
  .modblo-logos__viewport {
    overflow: hidden;
    -webkit-mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
    mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
  }
  .modblo-logos__track {
    display: flex; gap: 56px; width: max-content;
    animation: modblo-logos-scroll {{ section.settings.speed | default: 36 }}s linear infinite;
  }
  .modblo-logos__cell {
    display: flex; align-items: center; justify-content: center;
    height: 40px; opacity: .65; transition: opacity .2s;
  }
  .modblo-logos__cell:hover { opacity: 1; }
  .modblo-logos__img { height: 100%; width: auto; object-fit: contain; filter: grayscale(1); transition: filter .2s; }
  .modblo-logos__cell:hover .modblo-logos__img { filter: none; }
  .modblo-logos__name { font-size: 18px; font-weight: 600; letter-spacing: -.01em; }
  @keyframes modblo-logos-scroll {
    from { transform: translate3d(0, 0, 0); }
    to { transform: translate3d(-50%, 0, 0); }
  }
  @media (prefers-reduced-motion: reduce) { .modblo-logos__track { animation: none; } }
</style>

{% schema %}
{
  "name": "Logo Marquee",
  "tag": "section",
  "settings": [
    { "type": "text", "id": "heading", "label": "Heading", "default": "Trusted by modern brands" },
    { "type": "range", "id": "speed", "label": "Animation speed (s)", "min": 12, "max": 80, "step": 4, "default": 36 },
    { "type": "color", "id": "bg", "label": "Background", "default": "#ffffff" },
    { "type": "color", "id": "fg", "label": "Foreground", "default": "#0b0b0c" }
  ],
  "blocks": [{
    "type": "logo",
    "name": "Logo",
    "settings": [
      { "type": "image_picker", "id": "image", "label": "Logo image" },
      { "type": "text", "id": "name", "label": "Name (alt / fallback)", "default": "Brand" },
      { "type": "url", "id": "link", "label": "Link" }
    ]
  }],
  "max_blocks": 24,
  "presets": [{
    "name": "Logo Marquee",
    "blocks": [
      { "type": "logo", "settings": { "name": "Linear" } },
      { "type": "logo", "settings": { "name": "Vercel" } },
      { "type": "logo", "settings": { "name": "Stripe" } },
      { "type": "logo", "settings": { "name": "Framer" } },
      { "type": "logo", "settings": { "name": "Replo" } },
      { "type": "logo", "settings": { "name": "Shopify" } }
    ]
  }]
}
{% endschema %}

What you can customize

Every setting below shows up in the Shopify theme editor. Change them without touching code.

SettingTypeDefault

Heading

heading

Text,

Animation speed (s)

speed

Slider36

Background

bg

Color picker,

Foreground

fg

Color picker,

SEO and accessibility notes

  • Duplicated track is aria-hidden so SR users don't hear logos twice.
  • prefers-reduced-motion disables the animation entirely.