CSS
Class hooks and CSS variables for theming the default components.
Nuxt Photo ships three CSS strategies, controlled by the css module option:
Tune the visual layer
Keep structure CSS, then override the small surface your design needs.
.gallery {
--np-lightbox-bg: #090d18;
--gallery-radius: 10px;
}
.gallery :deep(.np-album__item) {
border-radius: var(--gallery-radius);
overflow: hidden;
}nuxtPhoto: {
css: 'structure' // 'none' | 'structure' | 'all'
}| Value | Loaded content |
|---|---|
'none' | No stylesheets. You write every rule yourself. |
'structure' | Layout + geometry only. Default. |
'all' | Structure + the default theme. |
Class naming
Every rendered element uses the np- prefix plus BEM-style double-underscore / double-dash notation:
.np-album → the album root
.np-album--rows → layout variant modifier
.np-album__row
.np-album__column
.np-album__item → each photo wrapper
.np-album__img → the inner <img>
.np-album__skeleton → measured-layout mount placeholder
.np-photo → <Photo> root
.np-photo__img
.np-photo__caption
.np-lightbox → the lightbox root
.np-lightbox__backdrop
.np-lightbox__ui → non-interactive full-screen chrome layer
.np-lightbox__topbar
.np-lightbox__actions
.np-lightbox__container
.np-lightbox__viewport
.np-lightbox__slide
.np-lightbox__media → zoom/pan wrapper for the active image
.np-lightbox__caption
.np-lightbox__btn
.np-lightbox__btn--close
.np-lightbox__fallback → image load failure message
[data-np-transition-layer] → internal FLIP transition visual
.np-carousel → carousel root
.np-carousel__viewport
.np-carousel__container
.np-carousel__slide
.np-carousel__media → main slide <img>
.np-carousel__controls
.np-carousel__arrow
.np-carousel__arrow--prev
.np-carousel__arrow--next
.np-carousel__counter
.np-carousel__caption
.np-carousel__dots
.np-carousel__thumb
.np-carousel__thumbs
.np-carousel__thumbs-viewport
.np-carousel__thumbs-container
.np-carousel__thumb-img
.np-carousel__thumb--selected
.np-carousel__dot
.np-carousel__dot--selectedInteractive lightbox children opt back into pointer events inside the full-screen UI layer. Keep that pattern if you replace the included markup: backdrop clicks should reach .np-lightbox__backdrop, while controls, captions, and media stay clickable.
You do not need to override these rules directly. Use the CSS variables and the itemClass, imgClass, slideClass, or controlsClass props for most customizations.
CSS variables
The theme CSS uses variables scoped to the relevant root. Override them globally in your app CSS or per-component.
Lightbox
.np-lightbox {
--np-backdrop-bg: rgba(0, 0, 0, 0.85);
--np-backdrop-filter: none; /* opt in with blur(16px) */
--np-btn-radius: 999px;
--np-btn-bg: rgba(255, 255, 255, 0.1);
--np-btn-hover-bg: rgba(255, 255, 255, 0.16);
--np-btn-color: white;
--np-btn-shadow: 0 1px 0 rgba(255, 255, 255, 0.08) inset, 0 16px 40px rgba(0, 0, 0, 0.24);
--np-btn-blur: 8px;
--np-btn-disabled-opacity: 0.45;
--np-counter-color: rgba(255, 255, 255, 0.72);
--np-img-radius: 16px;
--np-img-shadow: 0 24px 80px rgba(0, 0, 0, 0.34), 0 2px 12px rgba(0, 0, 0, 0.28);
--np-caption-color: white;
--np-caption-heading-size: 22px;
--np-caption-secondary: rgba(255, 255, 255, 0.72);
}Override any of them in your global CSS:
/* Warmer lightbox chrome */
.np-lightbox {
--np-backdrop-bg: rgba(40, 20, 10, 0.92);
--np-btn-bg: rgba(255, 255, 255, 0.08);
--np-img-radius: 4px;
}Carousel
.np-carousel {
--np-carousel-gap: 0.75rem;
--np-carousel-slide-size: 100%;
--np-carousel-slide-aspect: 16 / 10;
--np-carousel-thumb-size: 5.5rem;
--np-carousel-thumb-gap: 0.5rem;
--np-carousel-radius: 0.5rem;
--np-carousel-surface: rgba(0, 0, 0, 0.55);
--np-carousel-surface-fg: #fff;
--np-carousel-thumb-border: rgba(0, 0, 0, 0.1);
}Slide size, aspect, and thumb size can also be set via props (slideSize, slideAspect, thumbSize). The prop wins over the variable.
Album
Albums are mostly structural - spacing and padding come from props. For ready-made components, structure CSS is part of the layout contract, not decorative theme CSS.
Why 'structure' is the minimum
The structure CSS contains layout rules that are difficult to reproduce with Tailwind or other utility CSS:
- Rows layout uses a trailing
<span style="flex-grow:9999">ghost to absorb remaining space. - Columns and masonry use nested
.np-album__columnchildren with explicit gap math. - The lightbox viewport coordinates CSS custom properties set by JavaScript (zoom state, pan offsets, gesture translate).
The css: 'none' setting requires a complete replacement for these rules. Use it only with a custom gallery CSS system.
Overriding with itemClass / imgClass / etc.
Ready-made components accept class-targeting props. They add to the default classes, so you extend rather than replace:
<PhotoAlbum
:photos="photos"
item-class="rounded-lg overflow-hidden shadow-lg"
img-class="transition-transform hover:scale-105"
/>Use this option for hover states, border treatments, and shadow effects that do not need custom layout calculations.
Scoped styles in your components
Vue scoped styles rewrite class selectors. Therefore, a <style scoped> block cannot target .np-album__item directly. Use :deep():
<style scoped>
.my-album :deep(.np-album__item) {
border: 2px solid var(--accent);
}
</style>Turning off everything
nuxtPhoto: {
css: 'none'
}'none' only when you provide a complete replacement.




