Skip to documentation content

Rendering Images

Rendering Images

Render CMS images with img and image_url, size every non-full-bleed image with a preset, and author Image Preset and Alt values.

CMS images are Image objects, not static files. Render them with the img and image_url methods so the image's presets, alt text, and CDN delivery all apply.

img for a tag, image_url for a bare URL
{% img %} takes an Image object, GUID, or name and outputs a complete <img> tag, optionally wrapped in a link, with presets and any extra attributes:

{% img entity.hero_image class: "hero-img" preset: "960x540-crop" %}

Use {% image_url %} only when the destination needs a URL string rather than a tag, such as a CSS background image or a hand-built srcset entry:

{% image_url var hero_url = entity.hero_image preset: "1920x720-crop" %}
<div class="hero" style="background-image: url('{{ hero_url }}');"></div>

Avoid two anti-patterns. A hardcoded path such as <img src="assets/img/logo.webp"> bypasses the Image object entirely, so nothing configured on the record applies and the reference breaks when the static file goes away. Resolving image_url into a variable and then writing <img src="{{ logo_url }}"> by hand rebuilds what img already outputs, with more room for an empty or stale binding.

Size every image that is not full-bleed
img always writes width and height attributes taken from the resolved image: the source file's own dimensions when no preset resizes it, or the preset's output dimensions when one does. Those attributes size the box before CSS aspect-ratio does, unless the stylesheet also sets an explicit height. A large source image placed in a card whose CSS relies on aspect-ratio alone therefore renders at close to its full native height.

Give every card, thumbnail, and listing image a preset sized for its slot, so the emitted width and height already match the design. When the design really should crop with CSS (object-fit) regardless of the source shape, set height: auto in that CSS so the attributes stop competing with the ratio.

Image presets
A preset code such as 960x540-crop or webp is the Code of an Image Preset record. The record's QueryString describes the transformation:
• Crop to exact dimensions: height=540&mode=crop&width=960
• Fit within bounds without cropping: maxheight=540&maxwidth=960
• Allow upscaling when cropping: add scale=both
• Convert the format: format=webp
• Grayscale: s.grayscale=ntsc
• Sepia: s.sepia=true

The preset option takes one or more codes, either repeated or space-separated in one string, so a resize and a format conversion can combine: {% img item.photo preset: "960x540-crop webp" %}. preset is an option on img and image_url, not a filter. A preset code with no matching Image Preset record is ignored and the original image is served, so create the record before relying on the code.

Alt text
Alt is a property of the Image record itself and Liquid reads it as image.alt. Write meaningful alt text on the Image when it is uploaded or imported, rather than passing the image's title as an alt attribute on every img call.