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

1:1
4:3
16:9
21:9
3:4
9:16
<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')
);
Playground

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')
);
Playground

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')
);
Playground

Standalone .img-fluid utility

Inline illustration
<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')
);
Playground

Markup

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.

ModifierRatio
.is-square1 / 1
.is-1by11 / 1
.is-5by45 / 4
.is-4by34 / 3
.is-3by23 / 2
.is-16by916 / 9
.is-21by921 / 9
.is-2by32 / 3
.is-3by43 / 4
.is-9by169 / 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:

custom ratio
<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.

ModifierSize
.is-16x1616px
.is-24x2424px
.is-32x3232px
.is-48x4848px
.is-64x6464px
.is-96x9696px
.is-128x128128px

Decorations

  • .is-rounded — applies $border-radius (default $global-border-radius, 5px) and overflow: hidden so corners clip the picture itself.
  • .is-circleborder-radius: 50% plus overflow: 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 alt on <img>. Use alt="" for purely decorative media so assistive tech skips it.
  • Under forced-colors: active the thumbnail border falls back to CanvasText so the frame stays visible (WCAG 1.4.11).

Variables

VariableDefaultNotes
$selector'.image'Wrapper class.
$ratiosMap of 10 entries (square9by16)Bulma-compatible names. Extend the map to add ratios.
$fixed-sizesMap of 7 entries (16x16128x128)CSS lengths; extend with rem-based scales or portrait slots.
$object-fitcoverDefault fill mode for media inside ratio'd or fixed-size wrappers.
$border-radius$global-border-radius (5px)Used by .is-rounded.
$thumbnail-padding0.25remInner padding inside the thumbnail frame.
$thumbnail-border-width$global-border-widthFrame stroke width.
$thumbnail-border-mix$global-border-mixFrame stroke tint (currentColor over transparent).
$thumbnail-backgroundvar(--kc-bg, transparent)Matte fill behind the picture.
$thumbnail-border-radius$border-radiusRounding on the outer frame.

Override example

app.scss
@use '@adnap/krysalicss/element/image' with (
  $object-fit: contain,
  $thumbnail-padding: 0.5rem,
  $thumbnail-border-radius: 8px,
);

Tokens consumed

TokenUsed for
--kc-image-ratioAspect ratio driver — set by each .is-<ratio> modifier and overridable inline for custom ratios.
--kc-fgThumbnail border tint (mixed against transparent at $thumbnail-border-mix alpha).
--kc-bgThumbnail matte background.