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 Liquid

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 %}

Theme editor settings

SettingTypeDefault

Heading

heading

text,

Animation speed (s)

speed

range36

Background

bg

color,

Foreground

fg

color,

SEO & accessibility notes

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