Changeset a64d705 in Klonkt


Ignore:
Timestamp:
06/28/2026 05:25:46 PM (2 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
600fbf3
Parents:
201ec06
Message:

feat(images): accent-gradient placeholder while covers load + fade-in

Cover tiles/cards now show an accent-coloured gradient placeholder while the image loads
(instead of a white flash), and the cover fades in once loaded. Cached images stay instant.
Makes image-heavy pages feel responsive even before thumbnails finish.

  • assets/css/style.css — grid-tile gradient placeholder; grid-tile-img white moved to img + fade
  • views/partials/post-card.ejs — post-list-cover gradient placeholder + img fade
  • views/shell.ejs — cover fade-in script (hide-while-loading, instant for cached); buster v=61
Location:
src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/assets/css/style.css

    r201ec06 ra64d705  
    23772377}
    23782378
    2379 /* Transparent covers (PNG logos etc.) sit on white everywhere so they don't blend
    2380    into a dark theme. Opaque covers fully cover the white — no visible change. */
     2379/* Transparent covers (PNG logos etc.) sit on white so they don't blend into a dark
     2380   theme. The white is on the IMG, so the tile's accent-gradient placeholder shows
     2381   while the image is still loading. */
    23812382.post-cover img,
    23822383.post-list-cover img,
    2383 .grid-tile:not(.grid-tile-gradient) { background-color: #fff; }
     2384.grid-tile-img { background-color: #fff; }
     2385/* Accent-gradient placeholder shown while the cover image loads (the image fades in
     2386   over it), instead of a white flash on cover tiles. */
     2387.grid-tile:not(.grid-tile-gradient) {
     2388    background-image: linear-gradient(135deg,
     2389        color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2, var(--paper))) 0%,
     2390        color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2, var(--paper))) 100%);
     2391}
    23842392/* Cover as a real <img> (not background-image): browsers downsample <img> with the
    2385    high-quality image pipeline, so high-res line-art covers don't go jagged when shrunk. */
    2386 .grid-tile-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; filter: blur(.4px); }
     2393   high-quality image pipeline, so high-res line-art covers don't go jagged when shrunk.
     2394   Fades in on load (.is-loading removed) so the placeholder shows meanwhile. */
     2395.grid-tile-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; filter: blur(.4px); transition: opacity .4s ease; }
     2396.grid-tile-img.is-loading { opacity: 0; }
    23872397.grid-tile:hover { transform: scale(0.98); }
    23882398.grid-tile-overlay {
  • src/views/partials/post-card.ejs

    r201ec06 ra64d705  
    138138    margin-right: calc(-1 * clamp(1.25rem, 4vw, 2rem));
    139139    width: calc(100% + 2 * clamp(1.25rem, 4vw, 2rem)) !important;
    140     background: var(--paper-2);
     140    /* Accent-gradient placeholder shown while the cover loads (the image fades in over it). */
     141    background-image: linear-gradient(135deg,
     142        color-mix(in srgb, var(--accent, #888) 22%, var(--paper-2)) 0%,
     143        color-mix(in srgb, var(--accent, #888) 6%, var(--paper-2)) 100%);
    141144  }
    142145  .post-list-cover img {
     
    144147    object-fit: cover;
    145148    display: block;
    146   }
     149    transition: opacity .4s ease;
     150  }
     151  .post-list-cover img.is-loading { opacity: 0; }
    147152
    148153  /* Re-apply rounded corners on slightly larger phones */
  • src/views/shell.ejs

    r201ec06 ra64d705  
    200200
    201201<!-- v9 stylesheet (full palette system) -->
    202 <link rel="stylesheet" href="/assets/css/style.css?v=60">
     202<link rel="stylesheet" href="/assets/css/style.css?v=61">
    203203<script>
    204204/* iOS safe-area, built by hand. env(safe-area-inset-top) resolves to 0 on this iOS in
     
    737737     click reveals instead of following the card link or firing htmx navigation. -->
    738738<script>
     739// Cover fade-in: a cover image that's still loading is hidden so the accent-gradient
     740// placeholder behind it shows; it fades in once loaded. Cached/complete images stay
     741// visible (no flash). Runs on load + htmx swaps.
     742(function () {
     743  if (window.__coverFadeWired) return; window.__coverFadeWired = true;
     744  function scan(root) {
     745    (root || document).querySelectorAll('.grid-tile-img, .post-list-cover img').forEach(function (img) {
     746      if (img.dataset.fade) return; img.dataset.fade = '1';
     747      if (img.complete && img.naturalWidth > 0) return;   // already loaded → leave visible
     748      img.classList.add('is-loading');
     749      var done = function () { img.classList.remove('is-loading'); };
     750      img.addEventListener('load', done, { once: true });
     751      img.addEventListener('error', done, { once: true });
     752    });
     753  }
     754  scan(document);
     755  document.body.addEventListener('htmx:afterSettle', function (e) { scan(e.target); });
     756})();
     757</script>
     758
     759<script>
    739760(function () {
    740761  if (window.__nsfwWired) return; window.__nsfwWired = true;
Note: See TracChangeset for help on using the changeset viewer.