# Kayan yazı şeridi: ücretsiz Shopify bölümü

> Sonsuz kayan metin, ikon ya da logo şeridi. Haber bandı, duyuru şeridi ya da logo duvarı olarak kullanın. Duraklatma düğmeli, saf CSS hareket.

Kayan yazı şeridi (Marquee), metin öğelerinden ve logolardan oluşan bir şeridi sonsuz döngüde kaydıran ücretsiz bir Shopify bölümüdür. Hareket saf CSS’tir, ekran okuyucular her öğeyi bir kez duyar ve animasyonları kapatan ziyaretçiler için durur. Her Online Store 2.0 temasında uygulama olmadan çalışır.

- **Kategori:** İçerik ve hikâye anlatımı
- **Kullanıldığı yerler:** Ana sayfa, Ürün, Koleksiyon, Her sayfa
- **Okuduğu veri:** Yalnızca içerik
- **Boyut:** 2 dosyada 27 KB, küçük bir betikle
- **Lisans:** MIT, © 2026 Lintel
- **Sayfa:** https://lintelagency.com/tr/kaynaklar/shopify-bolumleri/kayan-yazi-seridi
- **Canlı demo:** https://lintelagency.com/resources/shopify-sections/demo/lib-marquee.html
- **Eklenme tarihi:** 2026-10-02

## Ne işe yarar

- Ana sayfa bölümleri arasında marka değerlerinden ya da kampanyalardan oluşan iddialı, eğik bir şerit
- Üst bilginin altında ücretsiz kargo ve iade bandı
- Üzerine gelince renklenen gri tonlamalı basın ya da satış noktası logoları satırı

## Tema düzenleyici ayarları

Bölüm tema düzenleyicide “Lib · Marquee” adıyla görünür. Kimlikler, türler, etiketler ve varsayılan değerler bölümün şemasından gelir. Etiketler tema düzenleyicide göründüğü gibi İngilizcedir.

### Motion

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `speed` | `range` | Speed (pixels per second) | `60` | 10–200 px, step 10 |
| `direction` | `select` | Direction | left | `left`, `right` |
| `pause_on_hover` | `checkbox` | Pause on hover | `true` |  |
| `pause_button` | `checkbox` | Show pause button | `true` |  |
| `tilt` | `select` | Tilt | 0 | `-3`, `-2`, `-1`, `0`, `1`, `2`, `3` |

### Separator

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `separator` | `select` | Separator between items | star | `none`, `dot`, `star`, `custom` |
| `separator_text` | `text` | Separator text | / |  |

### Text

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `text_size` | `select` | Text size on desktop | large | `small`, `medium`, `large`, `xlarge`, `huge` |
| `text_size_mobile` | `select` | Text size on mobile | medium | `small`, `medium`, `large`, `xlarge`, `huge` |
| `font_weight` | `select` | Font weight | 600 | `400`, `500`, `600`, `700`, `800` |
| `uppercase` | `checkbox` | Uppercase | `false` |  |
| `heading_font` | `checkbox` | Use the theme's heading font | `false` |  |

### Layout

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `gap` | `range` | Space between items | `32` | 8–120 px, step 4 |
| `band_padding` | `range` | Strip inner padding | `18` | 0–64 px, step 2 |
| `logo_height` | `range` | Logo height | `40` | 16–120 px, step 4 |
| `grayscale` | `checkbox` | Show logos in grayscale, color on hover | `true` |  |
| `fade_edges` | `checkbox` | Fade the left and right edges | `false` |  |

### Colors

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `color_bg` | `color` | Strip background | #1C1917 |  |
| `color_bg_gradient` | `color_background` | Strip background gradient | – |  |
| `color_text` | `color` | Text | #FAFAF9 |  |
| `color_accent` | `color` | Separator | #F59E0B |  |
| `color_section_bg` | `color` | Section background | – |  |
| `border_top` | `checkbox` | Border on top | `false` |  |
| `border_bottom` | `checkbox` | Border on bottom | `false` |  |
| `color_border` | `color` | Border | #44403C |  |

### Spacing and visibility

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `padding_top` | `range` | Top padding on desktop | `0` | 0–200 px, step 4 |
| `padding_bottom` | `range` | Bottom padding on desktop | `0` | 0–200 px, step 4 |
| `padding_top_mobile` | `range` | Top padding on mobile | `0` | 0–160 px, step 4 |
| `padding_bottom_mobile` | `range` | Bottom padding on mobile | `0` | 0–160 px, step 4 |
| `show_on` | `select` | Show on | all | `all`, `desktop`, `mobile` |
| `anchor_id` | `text` | Anchor ID | – |  |

## Bloklar

Toplamda en fazla 16 blok.

### Text item (`text`)

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `text` | `inline_richtext` | Text | Free shipping over $75 |  |
| `icon` | `text` | Icon or emoji | – |  |
| `icon_image` | `image_picker` | Icon image | – |  |
| `link` | `url` | Link | – |  |
| `new_tab` | `checkbox` | Open link in a new tab | `false` |  |

### Logo or image (`image`)

| Kimlik | Tür | Etiket | Varsayılan | Seçenekler ya da aralık |
| --- | --- | --- | --- | --- |
| `image` | `image_picker` | Image | – |  |
| `custom_height` | `checkbox` | Use a custom height | `false` |  |
| `height` | `range` | Height | `48` | 16–160 px, step 4 |
| `link` | `url` | Link | – |  |
| `new_tab` | `checkbox` | Open link in a new tab | `false` |  |

## Kurulum

### Shopify yönetim panelinde

1. Canlı temanızda değil, bir kopyasında çalışın: Shopify yönetim panelinde **Online Mağaza > Temalar** sayfasına gidin, mevcut temanızın **…** menüsünü açın ve **Kopya oluştur**’u seçin.
2. Kopyada **…** menüsünü açın ve **Kodu düzenle**’yi seçin.
3. `sections` klasörüne `lib-marquee.liquid` adında yeni bir dosya ekleyin, aşağıdaki kaynak koddan `sections/lib-marquee.liquid` içeriğini yapıştırıp kaydedin.
4. `lib-image.liquid` dosyalarını da aynı şekilde `snippets` klasörüne ekleyin. Başka bir Lib bölümünden gelen aynı adlı bir snippet zaten varsa aynı dosyadır; tek kopya yeterli.
5. Kopyada **Özelleştir**’i açın, **Bölüm ekle**’yi seçin ve **Lib · Marquee** bölümünü ekleyin. Örnek içeriği kendi içeriğinizle değiştirin, renkleri ayarlayın.
6. Kopyayı önizleyin, her şey doğru göründüğünde yayınlayın.

### Shopify CLI ile

Yerel tema klasörünüzde dosyaları indirin ve yalnızca bunları yayında olmayan bir temaya gönderin (temanın kimliğini `shopify theme list` gösterir):

```sh
curl -fsSL -o sections/lib-marquee.liquid https://lintelagency.com/resources/shopify-sections/files/lib-marquee.liquid
curl -fsSL -o snippets/lib-image.liquid https://lintelagency.com/resources/shopify-sections/files/lib-image.liquid
shopify theme push --theme <unpublished-theme-id> --only sections/lib-marquee.liquid --only snippets/lib-image.liquid
```

Canlı temaya asla göndermeyin: her zaman yayında olmayan bir temanın kimliğini verin, `--live` ya da `--allow-live` kullanmayın. Ardından bölümü yukarıdaki gibi tema düzenleyicide ekleyin.

## Dosyalar

- [sections/lib-marquee.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-marquee.liquid): `sections/` klasörüne
- [snippets/lib-image.liquid](https://lintelagency.com/resources/shopify-sections/files/lib-image.liquid): `snippets/` klasörüne

## Sık sorulan sorular

### Kayan yazı şeridi JavaScript gerektirir mi?

Hayır. Kaydırma bir CSS animasyonudur. Tek script, isteğe bağlı duraklatma düğmesi için küçük bir custom element’tir; o olmadan düğme gizli kalır ve şerit yine kayar.

### Ekran okuyucu ve klavye kullanıcıları bunu nasıl deneyimler?

Öğeler ekranı dolduracak şekilde tekrarlanır, ama her tekrar ekran okuyuculardan gizlenir ve bağlantıları sekme sırasından çıkarılır; böylece her öğe bir kez okunur ve bir kez odaklanır. Şerit, bağlantılarından biri klavye odağındayken durur ve ziyaretçiler onu duraklatma düğmesiyle durdurabilir.

### Ziyaretçide azaltılmış hareket açıksa ne olur?

prefers-reduced-motion ile animasyon kapanır, tekrarlar gizlenir ve öğeler ihtiyaç duydukları kadar ortalanmış satıra yayılır.

### Kaç öğe ekleyebilirim, metin ve logoları karıştırabilir miyim?

Metin öğeleri ile logo ya da görsel öğelerinin herhangi bir karışımında en fazla 16 blok. Her öğenin kendi bağlantısı olabilir ve logolar özel bir yükseklik kullanabilir.

### Hız ayarı her metin için tam olarak aynı mı kalır?

Döngü uzunluğu Liquid’de metin uzunluğu, yazı boyutu ve logo boyutlarından tahmin edilir; bu yüzden saniyede piksel cinsinden hız kesin değil, yaklaşıktır.

## Kaynak kod

### sections/lib-marquee.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{%- comment -%}
  Marquee: an endless strip of text items and/or logos. Text ticker, announcement strip or logo wall.
  Pure CSS animation: the item group is repeated enough times to cover a very wide screen twice,
  and the track slides by exactly half its width, so the loop has no seam.
  Screen readers get the first group only; every copy is aria-hidden and its links are out of the tab order.
  With prefers-reduced-motion the strip stops and the single group wraps onto several lines.
  An optional pause button (tiny custom element) lets visitors stop the motion.
  Depends on: snippets/lib-image.liquid
{%- endcomment -%}

{%- liquid
  assign s = section.settings
  assign eager = false
  if section.index <= 2
    assign eager = true
  endif

  comment
    Estimate the width of one item group in px, so the group is repeated enough times
    to fill wide screens and the loop runs at roughly the chosen speed.
  endcomment
  case s.text_size
    when 'small'
      assign fs = 14
    when 'medium'
      assign fs = 20
    when 'large'
      assign fs = 32
    when 'xlarge'
      assign fs = 56
    else
      assign fs = 96
  endcase
  assign cw = fs | times: 5 | divided_by: 10 | floor
  if s.uppercase
    assign cw = fs | times: 6 | divided_by: 10 | floor
  endif

  assign sep_px = 0
  case s.separator
    when 'dot'
      assign sep_px = fs | divided_by: 2 | floor
    when 'star'
      assign sep_px = fs
    when 'custom'
      assign sep_chars = s.separator_text | size
      assign sep_px = sep_chars | times: cw
  endcase
  if s.separator != 'none'
    assign sep_px = sep_px | plus: s.gap
  endif

  assign group_px = 0
  for block in section.blocks
    if block.type == 'image'
      assign h = s.logo_height
      if block.settings.custom_height
        assign h = block.settings.height
      endif
      assign ratio = 3
      if block.settings.image != blank and block.settings.image.aspect_ratio
        assign ratio = block.settings.image.aspect_ratio
      endif
      assign w = h | times: ratio | ceil
    else
      assign chars = block.settings.text | strip_html | size
      if block.settings.icon != blank or block.settings.icon_image != blank
        assign chars = chars | plus: 2
      endif
      assign w = chars | times: cw
    endif
    assign group_px = group_px | plus: w | plus: s.gap | plus: sep_px
  endfor
  if group_px < 1
    assign group_px = 1
  endif

  assign reps = 3200 | plus: group_px | minus: 1 | divided_by: group_px | floor
  if reps < 1
    assign reps = 1
  elsif reps > 16
    assign reps = 16
  endif
  assign copies = reps | times: 2
  assign half_px = reps | times: group_px
  assign duration = half_px | times: 1.0 | divided_by: s.speed | round: 1

  assign tilt = s.tilt | default: '0'
-%}

<div
  class="lib-marquee"
  {% if s.anchor_id != blank %}
    id="{{ s.anchor_id | handleize }}"
  {% endif %}
  data-show="{{ s.show_on }}"
  data-direction="{{ s.direction }}"
  data-size="{{ s.text_size }}"
  data-size-m="{{ s.text_size_mobile }}"
  {% if s.pause_on_hover %}
    data-hover-pause
  {% endif %}
  {% if s.uppercase %}
    data-upper
  {% endif %}
  {% if s.heading_font %}
    data-heading-font
  {% endif %}
  {% if s.grayscale %}
    data-gray
  {% endif %}
  {% if s.fade_edges %}
    data-fade
  {% endif %}
  {% if tilt != '0' %}
    data-tilted
  {% endif %}
  {% if s.border_top %}
    data-border-top
  {% endif %}
  {% if s.border_bottom %}
    data-border-bottom
  {% endif %}
  style="
    --lib-section-bg: {{ s.color_section_bg | default: 'transparent' }};
    --lib-bg: {{ s.color_bg }};
    {% if s.color_bg_gradient != blank %}--lib-bg-image: {{ s.color_bg_gradient }};{% endif %}
    --lib-text: {{ s.color_text }};
    --lib-accent: {{ s.color_accent }};
    --lib-border: {{ s.color_border }};
    --lib-weight: {{ s.font_weight }};
    --lib-gap: {{ s.gap }}px;
    --lib-logo-h: {{ s.logo_height }}px;
    --lib-band-py: {{ s.band_padding }}px;
    --lib-duration: {{ duration }}s;
    --lib-tilt: {{ tilt }}deg;
    --lib-pt: {{ s.padding_top }}px;
    --lib-pb: {{ s.padding_bottom }}px;
    --lib-pt-m: {{ s.padding_top_mobile }}px;
    --lib-pb-m: {{ s.padding_bottom_mobile }}px;
  "
>
  <div class="lib-marquee__band">
    {%- if section.blocks.size > 0 -%}
      <div class="lib-marquee__viewport">
        <div class="lib-marquee__track">
          {%- for copy in (1..copies) -%}
            <ul
              class="lib-marquee__group"
              {% if copy > 1 %}
                aria-hidden="true"
              {% endif %}
            >
              {%- for block in section.blocks -%}
                {%- liquid
                  assign b = block.settings
                  assign tag = 'span'
                  if b.link != blank
                    assign tag = 'a'
                  endif
                -%}
                <li
                  class="lib-marquee__item lib-marquee__item--{{ block.type }}"
                  {% if copy == 1 %}
                    {{ block.shopify_attributes }}
                  {% endif %}
                >
                  <{{ tag }}
                    class="lib-marquee__content"
                    {% if tag == 'a' %}
                      href="{{ b.link }}"
                      {% if b.new_tab %}
                        target="_blank" rel="noopener"
                      {% endif %}
                      {% if copy > 1 %}
                        tabindex="-1"
                      {% endif %}
                    {% endif %}
                  >
                    {%- if block.type == 'image' -%}
                      <span
                        class="lib-marquee__logo"
                        {% if b.custom_height %}
                          style="--lib-logo-h: {{ b.height }}px;"
                        {% endif %}
                      >
                        {%- liquid
                          assign img_eager = false
                          if eager and copy == 1
                            assign img_eager = true
                          endif
                          render 'lib-image', image: b.image, class: 'lib-marquee__img', sizes: '240px', eager: img_eager, placeholder: 'image'
                        -%}
                      </span>
                    {%- else -%}
                      {%- if b.icon_image != blank -%}
                        {{ b.icon_image | image_url: width: 96 | image_tag: class: 'lib-marquee__icon lib-marquee__icon--img', loading: 'lazy', alt: '' }}
                      {%- elsif b.icon != blank -%}
                        <span class="lib-marquee__icon" aria-hidden="true">{{ b.icon | escape }}</span>
                      {%- endif -%}
                      <span class="lib-marquee__text">{{ b.text }}</span>
                    {%- endif -%}
                  </{{ tag }}>
                  {%- case s.separator -%}
                    {%- when 'dot' -%}
                      <span class="lib-marquee__sep lib-marquee__sep--dot" aria-hidden="true"></span>
                    {%- when 'star' -%}
                      <span class="lib-marquee__sep lib-marquee__sep--star" aria-hidden="true">
                        <svg viewBox="0 0 24 24" width="24" height="24" focusable="false"><path d="M12 1.5c.6 5.6 4.9 9.9 10.5 10.5-5.6.6-9.9 4.9-10.5 10.5C11.4 16.9 7.1 12.6 1.5 12 7.1 11.4 11.4 7.1 12 1.5Z" fill="currentColor"/></svg>
                      </span>
                    {%- when 'custom' -%}
                      {%- if s.separator_text != blank -%}
                        <span class="lib-marquee__sep lib-marquee__sep--text" aria-hidden="true">{{ s.separator_text | escape }}</span>
                      {%- endif -%}
                  {%- endcase -%}
                </li>
              {%- endfor -%}
            </ul>
          {%- endfor -%}
        </div>
      </div>
      {%- if s.pause_button -%}
        <lib-marquee-pause class="lib-marquee__pause">
          <button type="button" class="lib-marquee__pause-btn" aria-pressed="false" aria-label="Pause the scrolling text">
            <svg class="lib-marquee__pause-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true" focusable="false"><path d="M4.5 3h2v10h-2zM9.5 3h2v10h-2z" fill="currentColor"/></svg>
            <svg class="lib-marquee__play-icon" viewBox="0 0 16 16" width="14" height="14" aria-hidden="true" focusable="false"><path d="M5 3l8 5-8 5z" fill="currentColor"/></svg>
          </button>
        </lib-marquee-pause>
      {%- endif -%}
    {%- endif -%}
  </div>
</div>

{% stylesheet %}
  .lib-marquee {
    background: var(--lib-section-bg);
    color: var(--lib-text);
    padding: var(--lib-pt) 0 var(--lib-pb);
    overflow-x: clip;
  }
  @media (max-width: 749px) {
    .lib-marquee { padding-top: var(--lib-pt-m); padding-bottom: var(--lib-pb-m); }
    .lib-marquee[data-show='desktop'] { display: none; }
  }
  @media (min-width: 750px) {
    .lib-marquee[data-show='mobile'] { display: none; }
  }

  /* The band is a little wider than the screen so a tilted strip has no visible ends. */
  .lib-marquee__band {
    position: relative;
    background-color: var(--lib-bg);
    background-image: var(--lib-bg-image, none);
    padding-block: var(--lib-band-py);
    transform: rotate(var(--lib-tilt));
  }
  .lib-marquee[data-tilted] .lib-marquee__band { margin-inline: -4vw; }
  .lib-marquee[data-border-top] .lib-marquee__band { border-top: 1px solid var(--lib-border); }
  .lib-marquee[data-border-bottom] .lib-marquee__band { border-bottom: 1px solid var(--lib-border); }

  .lib-marquee__viewport { overflow: hidden; }
  .lib-marquee[data-fade] .lib-marquee__viewport {
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  }

  .lib-marquee__track {
    display: flex;
    width: max-content;
    animation: lib-marquee-scroll var(--lib-duration) linear infinite;
  }
  .lib-marquee[data-direction='right'] .lib-marquee__track { animation-direction: reverse; }
  .lib-marquee[data-hover-pause] .lib-marquee__viewport:hover .lib-marquee__track,
  .lib-marquee__viewport:focus-within .lib-marquee__track,
  .lib-marquee[data-paused] .lib-marquee__track { animation-play-state: paused; }
  @keyframes lib-marquee-scroll {
    to { transform: translateX(-50%); }
  }

  .lib-marquee__group {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .lib-marquee__item {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    gap: var(--lib-gap);
    padding-inline-end: var(--lib-gap);
    white-space: nowrap;
  }

  /* Type: desktop size, then a separate mobile size. */
  .lib-marquee__band {
    --lib-fs: 1.25rem;
    font-size: var(--lib-fs);
    font-weight: var(--lib-weight);
    line-height: 1.15;
  }
  .lib-marquee[data-size='small'] .lib-marquee__band { --lib-fs: 0.875rem; }
  .lib-marquee[data-size='medium'] .lib-marquee__band { --lib-fs: 1.25rem; }
  .lib-marquee[data-size='large'] .lib-marquee__band { --lib-fs: 2rem; }
  .lib-marquee[data-size='xlarge'] .lib-marquee__band { --lib-fs: clamp(2.5rem, 4.5vw, 3.5rem); }
  .lib-marquee[data-size='huge'] .lib-marquee__band { --lib-fs: clamp(3rem, 7.5vw, 6rem); }
  @media (max-width: 749px) {
    .lib-marquee[data-size-m='small'] .lib-marquee__band { --lib-fs: 0.8125rem; }
    .lib-marquee[data-size-m='medium'] .lib-marquee__band { --lib-fs: 1.0625rem; }
    .lib-marquee[data-size-m='large'] .lib-marquee__band { --lib-fs: 1.5rem; }
    .lib-marquee[data-size-m='xlarge'] .lib-marquee__band { --lib-fs: 2rem; }
    .lib-marquee[data-size-m='huge'] .lib-marquee__band { --lib-fs: 2.75rem; }
  }
  .lib-marquee[data-upper] .lib-marquee__band { text-transform: uppercase; letter-spacing: 0.04em; }
  .lib-marquee[data-heading-font] .lib-marquee__band {
    font-family: var(--font-heading-family, inherit);
    font-style: var(--font-heading-style, normal);
  }

  .lib-marquee__content {
    display: inline-flex;
    align-items: center;
    gap: 0.45em;
    color: inherit;
    text-decoration: none;
  }
  a.lib-marquee__content:hover .lib-marquee__text { text-decoration: underline; text-underline-offset: 0.18em; text-decoration-thickness: 0.06em; }
  a.lib-marquee__content:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; border-radius: 2px; }
  .lib-marquee__text p { display: inline; margin: 0; }
  .lib-marquee__icon { line-height: 1; }
  .lib-marquee__icon--img { width: 1.1em; height: 1.1em; object-fit: contain; }

  .lib-marquee__sep { display: inline-flex; align-items: center; justify-content: center; color: var(--lib-accent); }
  .lib-marquee__sep--dot { width: 0.3em; height: 0.3em; border-radius: 50%; background: currentColor; }
  .lib-marquee__sep--star svg { width: 0.75em; height: 0.75em; }

  /* Logos keep their own proportions at a fixed height. */
  .lib-marquee__logo { display: block; height: var(--lib-logo-h); }
  .lib-marquee__img {
    display: block;
    height: 100%;
    width: auto;
    max-width: none;
    object-fit: contain;
    transition: filter 0.3s ease, opacity 0.3s ease;
  }
  .lib-marquee__img:is(svg) {
    aspect-ratio: 3 / 1;
    fill: color-mix(in srgb, var(--lib-text) 25%, transparent);
    border-radius: 4px;
  }
  .lib-marquee[data-gray] .lib-marquee__img { filter: grayscale(1); opacity: 0.65; }
  .lib-marquee[data-gray] .lib-marquee__item--image:hover .lib-marquee__img { filter: none; opacity: 1; }

  /* Pause button */
  .lib-marquee__pause {
    position: absolute;
    inset-block: 0;
    inset-inline-end: 0;
    display: flex;
    align-items: center;
    padding-inline: 2.5rem 0.75rem;
    background: linear-gradient(90deg, transparent, var(--lib-bg) 55%);
  }
  .lib-marquee[data-tilted] .lib-marquee__pause { inset-inline-end: 4vw; }
  .lib-marquee__pause:not(:defined) { display: none; }
  .lib-marquee__pause-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 1px solid color-mix(in srgb, var(--lib-text) 30%, transparent);
    border-radius: 50%;
    background: var(--lib-bg);
    color: var(--lib-text);
    cursor: pointer;
  }
  .lib-marquee__pause-btn:hover { border-color: currentColor; }
  .lib-marquee__pause-btn:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
  .lib-marquee__play-icon,
  .lib-marquee__pause-btn[aria-pressed='true'] .lib-marquee__pause-icon { display: none; }
  .lib-marquee__pause-btn[aria-pressed='true'] .lib-marquee__play-icon { display: block; }

  /* Reduced motion: no animation; one group, wrapped and centred. */
  @media (prefers-reduced-motion: reduce) {
    .lib-marquee__track { animation: none; width: auto; justify-content: center; padding-inline: 1rem; }
    .lib-marquee__group { flex-wrap: wrap; justify-content: center; row-gap: 0.5em; flex-shrink: 1; }
    .lib-marquee__group[aria-hidden] { display: none; }
    .lib-marquee__item { white-space: normal; }
    .lib-marquee__item:last-child { padding-inline-end: 0; }
    .lib-marquee__item:last-child .lib-marquee__sep { display: none; }
    .lib-marquee[data-fade] .lib-marquee__viewport { -webkit-mask-image: none; mask-image: none; }
    .lib-marquee__pause { display: none; }
    .lib-marquee__img { transition: none; }
  }
{% endstylesheet %}

{% javascript %}
  if (!customElements.get('lib-marquee-pause')) {
    customElements.define(
      'lib-marquee-pause',
      class extends HTMLElement {
        connectedCallback() {
          const button = this.querySelector('button');
          const root = this.closest('.lib-marquee');
          if (!button || !root || this.bound) return;
          this.bound = true;
          button.addEventListener('click', () => {
            const paused = button.getAttribute('aria-pressed') !== 'true';
            button.setAttribute('aria-pressed', String(paused));
            button.setAttribute('aria-label', paused ? 'Play the scrolling text' : 'Pause the scrolling text');
            root.toggleAttribute('data-paused', paused);
          });
        }
      }
    );
  }
{% endjavascript %}

{% schema %}
{
  "name": "Lib · Marquee",
  "tag": "section",
  "class": "lib-section",
  "max_blocks": 16,
  "settings": [
    { "type": "header", "content": "Motion" },
    { "type": "range", "id": "speed", "label": "Speed (pixels per second)", "min": 10, "max": 200, "step": 10, "unit": "px", "default": 60 },
    {
      "type": "select",
      "id": "direction",
      "label": "Direction",
      "options": [
        { "value": "left", "label": "Right to left" },
        { "value": "right", "label": "Left to right" }
      ],
      "default": "left"
    },
    { "type": "checkbox", "id": "pause_on_hover", "label": "Pause on hover", "default": true },
    {
      "type": "checkbox",
      "id": "pause_button",
      "label": "Show pause button",
      "info": "Lets visitors stop the motion (recommended for accessibility). The strip also pauses while a link in it has keyboard focus, and stays still for visitors who turn off animations.",
      "default": true
    },
    {
      "type": "select",
      "id": "tilt",
      "label": "Tilt",
      "info": "Rotates the strip. Add top and bottom padding so the corners are not cut off.",
      "options": [
        { "value": "-3", "label": "-3°" },
        { "value": "-2", "label": "-2°" },
        { "value": "-1", "label": "-1°" },
        { "value": "0", "label": "None" },
        { "value": "1", "label": "1°" },
        { "value": "2", "label": "2°" },
        { "value": "3", "label": "3°" }
      ],
      "default": "0"
    },

    { "type": "header", "content": "Separator" },
    {
      "type": "select",
      "id": "separator",
      "label": "Separator between items",
      "options": [
        { "value": "none", "label": "None" },
        { "value": "dot", "label": "Dot" },
        { "value": "star", "label": "Star" },
        { "value": "custom", "label": "Custom text" }
      ],
      "default": "star"
    },
    { "type": "text", "id": "separator_text", "label": "Separator text", "default": "/", "visible_if": "{{ section.settings.separator == 'custom' }}" },

    { "type": "header", "content": "Text" },
    {
      "type": "select",
      "id": "text_size",
      "label": "Text size on desktop",
      "options": [
        { "value": "small", "label": "Small" },
        { "value": "medium", "label": "Medium" },
        { "value": "large", "label": "Large" },
        { "value": "xlarge", "label": "Extra large" },
        { "value": "huge", "label": "Huge" }
      ],
      "default": "large"
    },
    {
      "type": "select",
      "id": "text_size_mobile",
      "label": "Text size on mobile",
      "options": [
        { "value": "small", "label": "Small" },
        { "value": "medium", "label": "Medium" },
        { "value": "large", "label": "Large" },
        { "value": "xlarge", "label": "Extra large" },
        { "value": "huge", "label": "Huge" }
      ],
      "default": "medium"
    },
    {
      "type": "select",
      "id": "font_weight",
      "label": "Font weight",
      "options": [
        { "value": "400", "label": "Regular" },
        { "value": "500", "label": "Medium" },
        { "value": "600", "label": "Semibold" },
        { "value": "700", "label": "Bold" },
        { "value": "800", "label": "Extra bold" }
      ],
      "default": "600"
    },
    { "type": "checkbox", "id": "uppercase", "label": "Uppercase", "default": false },
    { "type": "checkbox", "id": "heading_font", "label": "Use the theme's heading font", "info": "Works in themes that define --font-heading-family (Dawn and most free themes). Otherwise the body font is used.", "default": false },

    { "type": "header", "content": "Layout" },
    { "type": "range", "id": "gap", "label": "Space between items", "min": 8, "max": 120, "step": 4, "unit": "px", "default": 32 },
    { "type": "range", "id": "band_padding", "label": "Strip inner padding", "min": 0, "max": 64, "step": 2, "unit": "px", "default": 18 },
    { "type": "range", "id": "logo_height", "label": "Logo height", "min": 16, "max": 120, "step": 4, "unit": "px", "default": 40 },
    { "type": "checkbox", "id": "grayscale", "label": "Show logos in grayscale, color on hover", "default": true },
    { "type": "checkbox", "id": "fade_edges", "label": "Fade the left and right edges", "default": false },

    { "type": "header", "content": "Colors" },
    { "type": "color", "id": "color_bg", "label": "Strip background", "default": "#1C1917" },
    { "type": "color_background", "id": "color_bg_gradient", "label": "Strip background gradient", "info": "Optional. Covers the strip background color." },
    { "type": "color", "id": "color_text", "label": "Text", "default": "#FAFAF9" },
    { "type": "color", "id": "color_accent", "label": "Separator", "default": "#F59E0B" },
    { "type": "color", "id": "color_section_bg", "label": "Section background", "info": "Optional. Shows above and below the strip, for example around a tilted strip." },
    { "type": "checkbox", "id": "border_top", "label": "Border on top", "default": false },
    { "type": "checkbox", "id": "border_bottom", "label": "Border on bottom", "default": false },
    { "type": "color", "id": "color_border", "label": "Border", "default": "#44403C" },

    { "type": "header", "content": "Spacing and visibility" },
    { "type": "range", "id": "padding_top", "label": "Top padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 0 },
    { "type": "range", "id": "padding_bottom", "label": "Bottom padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 0 },
    { "type": "range", "id": "padding_top_mobile", "label": "Top padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 0 },
    { "type": "range", "id": "padding_bottom_mobile", "label": "Bottom padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 0 },
    {
      "type": "select",
      "id": "show_on",
      "label": "Show on",
      "options": [
        { "value": "all", "label": "All devices" },
        { "value": "desktop", "label": "Desktop only" },
        { "value": "mobile", "label": "Mobile only" }
      ],
      "default": "all"
    },
    { "type": "text", "id": "anchor_id", "label": "Anchor ID", "info": "Optional. Link to this section with #your-id." }
  ],
  "blocks": [
    {
      "type": "text",
      "name": "Text item",
      "settings": [
        { "type": "inline_richtext", "id": "text", "label": "Text", "default": "Free shipping over $75" },
        { "type": "text", "id": "icon", "label": "Icon or emoji", "info": "Optional. One character shown before the text." },
        { "type": "image_picker", "id": "icon_image", "label": "Icon image", "info": "Optional. Replaces the icon character." },
        { "type": "url", "id": "link", "label": "Link" },
        { "type": "checkbox", "id": "new_tab", "label": "Open link in a new tab", "default": false, "visible_if": "{{ block.settings.link != blank }}" }
      ]
    },
    {
      "type": "image",
      "name": "Logo or image",
      "settings": [
        { "type": "image_picker", "id": "image", "label": "Image", "info": "Alt text comes from the image. A transparent PNG or SVG logo works best." },
        { "type": "checkbox", "id": "custom_height", "label": "Use a custom height", "default": false },
        { "type": "range", "id": "height", "label": "Height", "min": 16, "max": 160, "step": 4, "unit": "px", "default": 48, "visible_if": "{{ block.settings.custom_height }}" },
        { "type": "url", "id": "link", "label": "Link" },
        { "type": "checkbox", "id": "new_tab", "label": "Open link in a new tab", "default": false, "visible_if": "{{ block.settings.link != blank }}" }
      ]
    }
  ],
  "presets": [
    {
      "name": "Lib · Marquee",
      "blocks": [
        { "type": "text", "settings": { "text": "Free shipping over $75" } },
        { "type": "text", "settings": { "text": "Hand-thrown in small batches" } },
        { "type": "text", "settings": { "text": "30-day returns" } },
        { "type": "text", "settings": { "text": "New: the <em>Linen</em> collection" } }
      ]
    }
  ]
}
{% endschema %}
```

### snippets/lib-image.liquid

```liquid
{%- comment -%}
  MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections
{%- endcomment -%}
{% doc %}
  Responsive image with optional art direction: a separate mobile image (below 750px),
  each honouring its own focal point from the theme editor. Falls back to a placeholder.

  @param {image} [image] - Desktop image (also used on mobile when no mobile image is set)
  @param {image} [image_mobile] - Mobile image, below 750px
  @param {string} [class] - Class for the img element
  @param {string} [sizes] - sizes attribute for the desktop image (default 100vw)
  @param {boolean} [eager] - Load immediately with high fetch priority (use for the first sections on a page)
  @param {string} [placeholder] - placeholder_svg_tag name when no image is set (default 'lifestyle-1')

  @example
  {% render 'lib-image', image: section.settings.image, image_mobile: section.settings.image_mobile, class: 'lib-hero__img', sizes: '(min-width: 990px) 50vw, 100vw', eager: true %}
{% enddoc %}

{%- liquid
  assign desktop = image
  if desktop == blank
    assign desktop = image_mobile
  endif
  assign img_sizes = sizes | default: '100vw'
  assign img_loading = 'lazy'
  assign img_priority = 'auto'
  if eager
    assign img_loading = 'eager'
    assign img_priority = 'high'
  endif
  assign art = false
  if image != blank and image_mobile != blank
    assign art = true
  endif
-%}

{%- if desktop != blank -%}
  <picture
    class="lib-picture{% if art %} lib-picture--art{% endif %}"
    {% if art %}
      style="--lib-pos-m: {{ image_mobile.presentation.focal_point | default: '50% 50%' }};"
    {% endif %}
  >
    {%- if art -%}
      <source
        media="(max-width: 749px)"
        srcset="
          {{ image_mobile | image_url: width: 375 }} 375w,
          {{ image_mobile | image_url: width: 750 }} 750w,
          {{ image_mobile | image_url: width: 1100 }} 1100w,
          {{ image_mobile | image_url: width: 1500 }} 1500w
        "
        sizes="100vw"
        width="{{ image_mobile.width }}"
        height="{{ image_mobile.height }}"
      >
    {%- endif -%}
    {{
      desktop
      | image_url: width: 2400
      | image_tag:
        class: class,
        loading: img_loading,
        fetchpriority: img_priority,
        sizes: img_sizes,
        widths: '600, 900, 1200, 1600, 2000, 2400'
    }}
  </picture>
{%- else -%}
  {{ placeholder | default: 'lifestyle-1' | placeholder_svg_tag: class }}
{%- endif -%}

{% stylesheet %}
  .lib-picture { display: contents; }
  @media (max-width: 749px) {
    /* image_tag sets the desktop focal point inline; the mobile image needs its own. */
    .lib-picture--art img { object-position: var(--lib-pos-m) !important; }
  }
{% endstylesheet %}
```

## Lisans

MIT Lisansı, © 2026 Lintel. Kendi mağazanızda ya da müşteri işlerinde ücretsiz kullanabilir, değiştirebilir ve yayınlayabilirsiniz; her dosyanın başındaki lisans satırını koruyun.
