Use The Platform

This page is a dedicated section to list some of the web platform features that I use to build my site.

The list are sorted alphabetically

  1. CSS :focus-within

    I'm using it to add visual aid when focusing dark mode selector. The reason is I use full size select with zero opacity to overlay the icon and text so when clicked it still open select options.

    Because select element is transparent, there's no visual feedback for focused element, so I added :focus-within on its parent and render the same outline in the icon + text.

    .parent select {
    opacity: 0;
    }
    .parent:focus-within .toggle {
    outline-color: var(--color-accent-primary);
    outline-offset: -2px;
    outline-style: auto;
    outline-width: 5px;
    }
  2. CSS background-clip: text

    Animated gradient for text color! It's an experimental feature, but it's amazing. I use this in my share button at the bottom of every blog post. For animation, I'm using CSS keyframe with infinite iteration count.

    .gradient {
    background-image: radial-gradient(circle at top right, var(--color-accent-primary), var(--color-accent-subtle));
    background-clip: text;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    }
  3. CSS clamp()

    This is used to automatically resize base font-size according to screen width without the need of media queries

    html {
    /* fallback */
    font-size: max(min(14px, 2vw), 17px);
    /* same as above, but reads better */
    font-size: clamp(14px, 2vw, 17px);
    }
  4. CSS Cubic Bezier

    You can simulate fake spring behavior by using cubic-bezier alone. I use this for Read More link in the homepage.

    .link svg {
    position: relative;
    opacity: 0;
    left: 3px;
    transition: all 0.3s cubic-bezier(0.33, 1.07, 0, 1.72);
    }
    .link:hover svg {
    opacity: 1;
    left: 6px;
    }
  5. CSS Custom Properties

    The obvious answer is theming.

    The less obvious answer is the ability to share values within same parent. This turns out to be pretty useful when I create element that break through its parent container width. This combined with calc() and max() allow me to bypass media query entirely to create responsive layout. See it here

    img[data-wide] {
    --max-width: 980px;
    position: relative;
    left: 50%;
    width: 100vw;
    max-width: var(--max-width);
    margin-left: max(-50vw, calc(var(--max-width) / -2));
    }
  6. CSS Paint API (Houdini)

    Fun experiment only. Using paint worklet, I was able to create randomized blob for ordered list background. Each list item will render different shape and will re-render on resize and dark mode switch (due to css variable change 🤯).

    ol:not([start]) {
    counter-reset: blob-counter;
    }
    ol li {
    counter-increment: blob-counter;
    }
    ol li::before {
    content: counter(blob-counter);
    background: paint(blob);
    }
  7. Hover Media Query

    Commonly used as progressive enhancement, to give different treatment to devices with different input types. I use this in my code block to display compile time error and few others.

    @media (hover: hover) {
    pre .error {
    display: none;
    }
    }
    const isHoverDisabled = window.matchMedia('(hover: hover)').matches === false;
  8. Intersection Observer

    This is used to fix iframe height issue for 3rd party embed. When rendering iframe, we can use onload to set the iframe height based on content height. Unfortunately this is not a foolproof method as some content add async style and scripts that causes layout + paint.

    By using Intersection Observer, we can recalculate content height after the iframe is visible on the screen.

    const observer = new IntersectionObserver(entries => {
    entries.forEach(entry => {
    if (entry.isIntersecting) {
    const currentFrameHeight = iframe.contentDocument?.body?.offsetHeight;
    if (currentFrameHeight && currentFrameHeight !== frameHeight) {
    setFrameHeight(currentFrameHeight);
    }
    }
    })
    });
    observer.observe(iframe);
  9. Web Share API

    At the bottom of every blog post, I added a share button using Web Share API. Browser support is pretty good on mobile devices, and I'm using tweet button and window popup as fallback.

    await navigator.share({
    url: window.location.href,
    text: shareText,
    title: document.title,
    });