Image
Responsive media wrapper. .image hosts an img,
video, iframe, or picture child and
caps it at the container width by default. Layered modifiers add explicit
aspect ratios, fixed square slots, and decorative framings. A standalone
.img-fluid utility ships for inline content authoring where
wrapping is overkill.
Live
Aspect-ratio variants
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.75rem;">
<figure class="image is-1by1" style="background: color-mix(in srgb, currentColor 8%, transparent);">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234A90E2'/%3E%3C/svg%3E" alt="1:1">
</figure>
<figure class="image is-4by3" style="background: color-mix(in srgb, currentColor 8%, transparent);">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 3'%3E%3Crect width='4' height='3' fill='%23E2A04A'/%3E%3C/svg%3E" alt="4:3">
</figure>
<figure class="image is-16by9" style="background: color-mix(in srgb, currentColor 8%, transparent);">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 9'%3E%3Crect width='16' height='9' fill='%234AE290'/%3E%3C/svg%3E" alt="16:9">
</figure>
<figure class="image is-21by9" style="background: color-mix(in srgb, currentColor 8%, transparent);">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 21 9'%3E%3Crect width='21' height='9' fill='%23E24A90'/%3E%3C/svg%3E" alt="21:9">
</figure>
<figure class="image is-3by4" style="background: color-mix(in srgb, currentColor 8%, transparent);">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 4'%3E%3Crect width='3' height='4' fill='%239B4AE2'/%3E%3C/svg%3E" alt="3:4">
</figure>
<figure class="image is-9by16" style="background: color-mix(in srgb, currentColor 8%, transparent);">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 16'%3E%3Crect width='9' height='16' fill='%234AE2E2'/%3E%3C/svg%3E" alt="9:16">
</figure>
</div> @use '@adnap/krysalicss' with (
$feature-list: ('base-reset', 'base-global', 'element-image')
); Fixed square sizes (avatars / chips)
<div style="display: flex; gap: 0.75rem; align-items: flex-end; flex-wrap: wrap;">
<figure class="image is-16x16"><img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234A90E2'/%3E%3C/svg%3E" alt=""></figure>
<figure class="image is-24x24"><img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234A90E2'/%3E%3C/svg%3E" alt=""></figure>
<figure class="image is-32x32"><img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234A90E2'/%3E%3C/svg%3E" alt=""></figure>
<figure class="image is-48x48"><img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234A90E2'/%3E%3C/svg%3E" alt=""></figure>
<figure class="image is-64x64"><img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234A90E2'/%3E%3C/svg%3E" alt=""></figure>
<figure class="image is-96x96"><img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234A90E2'/%3E%3C/svg%3E" alt=""></figure>
<figure class="image is-128x128"><img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234A90E2'/%3E%3C/svg%3E" alt=""></figure>
</div> @use '@adnap/krysalicss' with (
$feature-list: ('base-reset', 'base-global', 'element-image')
); Decorative modifiers: rounded / circle / thumbnail
<div style="display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap;">
<figure class="image is-64x64 is-rounded">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234A90E2'/%3E%3C/svg%3E" alt="">
</figure>
<figure class="image is-64x64 is-circle">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%23E24A90'/%3E%3C/svg%3E" alt="">
</figure>
<figure class="image is-96x96 is-thumbnail">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%234AE290'/%3E%3C/svg%3E" alt="">
</figure>
<figure class="image is-96x96 has-thumbnail">
<img src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 1'%3E%3Crect width='1' height='1' fill='%23E2A04A'/%3E%3C/svg%3E" alt="">
</figure>
</div> @use '@adnap/krysalicss' with (
$feature-list: ('base-reset', 'base-global', 'element-image')
); Standalone .img-fluid utility
<img class="img-fluid" alt="Inline illustration" src="data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 4'%3E%3Crect width='16' height='4' fill='%234A90E2'/%3E%3C/svg%3E"> @use '@adnap/krysalicss' with (
$feature-list: ('base-reset', 'base-global', 'element-image')
); Markup
<!-- No-ratio: wrapper takes the picture's intrinsic height, scales down only. -->
<figure class="image">
<img src="/cover.jpg" alt="Cover">
</figure>
<!-- Aspect-ratio variant: picture fills the slot with object-fit: cover. -->
<figure class="image is-16by9">
<img src="/cover.jpg" alt="Cover">
</figure>
<!-- Fixed-square slot for avatars / icon tiles. -->
<figure class="image is-64x64 is-circle">
<img src="/avatar.jpg" alt="">
</figure>
<!-- Standalone fluid utility for inline content authoring (Bootstrap parity). -->
<img class="img-fluid" src="/illustration.svg" alt=""> Modifiers
Aspect ratios
Each .is-<ratio> sets both --kc-image-ratio and the aspect-ratio
property, then re-targets the media child to fill the wrapper box with
object-fit: cover (configurable). The ten ratios ship as Bulma-compatible
class names; pick the one that matches your media slot.
| Modifier | Ratio |
|---|---|
.is-square | 1 / 1 |
.is-1by1 | 1 / 1 |
.is-5by4 | 5 / 4 |
.is-4by3 | 4 / 3 |
.is-3by2 | 3 / 2 |
.is-16by9 | 16 / 9 |
.is-21by9 | 21 / 9 |
.is-2by3 | 2 / 3 |
.is-3by4 | 3 / 4 |
.is-9by16 | 9 / 16 |
For ratios outside the shipped roster, drop a class and inline the variable
instead — every aspect-ratio rule keys off --kc-image-ratio, so the same
fill / object-fit behaviour applies:
<figure class="image" style="--kc-image-ratio: 7/3; aspect-ratio: var(--kc-image-ratio);">
<img src="/cover.jpg" alt="">
</figure> Fixed sizes
Pinned square slots — useful for avatars, icon chips, tile lists where the
intrinsic media dimensions must not leak into the layout. The child media
covers the slot with object-fit: cover.
| Modifier | Size |
|---|---|
.is-16x16 | 16px |
.is-24x24 | 24px |
.is-32x32 | 32px |
.is-48x48 | 48px |
.is-64x64 | 64px |
.is-96x96 | 96px |
.is-128x128 | 128px |
Decorations
.is-rounded— applies$border-radius(default$global-border-radius, 5px) andoverflow: hiddenso corners clip the picture itself..is-circle—border-radius: 50%plusoverflow: hidden. Pair with a fixed square size for predictable avatars..is-thumbnail/.has-thumbnail— Bootstrap-parity framed picture: border + inner padding + matted background. Two class names ship for the same effect so consumers can pick the convention that reads best in their markup (state-style vs decoration-style).
.img-fluid
Standalone responsive utility — display: block; max-inline-size: 100%; block-size: auto. Use inside MDX or articles where wrapping each
<img> in .image is overkill. No !important, so a fixed hero crop
remains overridable.
Custom ratio via --kc-image-ratio
--kc-image-ratio is exposed as the single source of truth for the
aspect-ratio variants. Setting it inline produces the same cover-fill
behaviour as the shipped .is-* classes — useful for editorial layouts
that need ratios the framework does not ship.
Accessibility
- Always set
alton<img>. Usealt=""for purely decorative media so assistive tech skips it. - Under
forced-colors: activethe thumbnail border falls back toCanvasTextso the frame stays visible (WCAG 1.4.11).
Variables
| Variable | Default | Notes |
|---|---|---|
$selector | '.image' | Wrapper class. |
$ratios | Map of 10 entries (square … 9by16) | Bulma-compatible names. Extend the map to add ratios. |
$fixed-sizes | Map of 7 entries (16x16 … 128x128) | CSS lengths; extend with rem-based scales or portrait slots. |
$object-fit | cover | Default fill mode for media inside ratio'd or fixed-size wrappers. |
$border-radius | $global-border-radius (5px) | Used by .is-rounded. |
$thumbnail-padding | 0.25rem | Inner padding inside the thumbnail frame. |
$thumbnail-border-width | $global-border-width | Frame stroke width. |
$thumbnail-border-mix | $global-border-mix | Frame stroke tint (currentColor over transparent). |
$thumbnail-background | var(--kc-bg, transparent) | Matte fill behind the picture. |
$thumbnail-border-radius | $border-radius | Rounding on the outer frame. |
Override example
@use '@adnap/krysalicss/element/image' with (
$object-fit: contain,
$thumbnail-padding: 0.5rem,
$thumbnail-border-radius: 8px,
); Tokens consumed
| Token | Used for |
|---|---|
--kc-image-ratio | Aspect ratio driver — set by each .is-<ratio> modifier and overridable inline for custom ratios. |
--kc-fg | Thumbnail border tint (mixed against transparent at $thumbnail-border-mix alpha). |
--kc-bg | Thumbnail matte background. |