• Natural sorting of strings that contain numbers in JavaScript

    In JavaScript, things get interesting when you need to sort strings that contain numbers in a way that matches human expectations.

    const files = ['IMG_2.png', 'IMG_1.png', 'IMG_10.png', 'IMG_20.png'];
    files.sort();
    // Output: ['IMG_1.png', 'IMG_10.png', 'IMG_2.png', 'IMG_20.png']

    This happens because, by default, when no compare function is provided, JavaScript’s array sort() method converts the elements into strings, then compares their sequences of UTF-16 code unit values.

    This behaviour is well documented on MDN.

    So, how do we sort arrays like the ones above in a more accurate, human-friendly order?

    This is where the compare() method of the Intl.Collator API with the numeric: true option shines. It provides the natural sorting behaviour that correctly handles numbers alongside other characters.

    When numeric: true is set, the collator detects numeric substrings inside the strings and parses those substrings as actual numbers, not as sequences of digits. And then it compares the numbers numerically, not character by character.

    const naturalOrder = new Intl.Collator(undefined, {
    	numeric: true,
    }).compare;
    
    const files = ['IMG_2.png', 'IMG_1.png', 'IMG_10.png', 'IMG_20.png'];
    files.sort((a, b) => naturalOrder(a, b));
    // Output: ['IMG_1.png', 'IMG_2.png', 'IMG_10.png', 'IMG_20.png']

    Hat tip to Jan Miksovsky, whose zero dependencies SSG project led me to discover this.

  • Note - Posted on

    Today I learned, grid-auto-columns and grid-auto-rows size implicit tracks as well as any explicit tracks that are not explicitly sized by by grid-template-rows or grid-template-columns.

    Until now, I was under the impression that grid-auto-rows and grid-auto-columns size only implicit grid tracks.

  • Why is `grid-row: 1/-1` not working?

    The grid-row grid-placement property is shorthand for grid-row-start and grid-row-end.

    .grid-item {
    	grid-row: 1/-1;
    	/* is equivalent to */
    	grid-row-start: 1;
    	grid-row-end: -1;
    }

    In the above declaration, we use integers to position and size the grid item by line numbers.

    As per the spec:

    Numeric indexes in the grid-placement properties count from the edges of the explicit grid. Positive indexes count from the start side (starting from 1 for the start-most explicit line), while negative indexes count from the end side (starting from -1 for the end-most explicit line).

    The important bit is the explicit grid. This begs the question …

    What is the explicit grid?

    As per the spec:

    The three properties grid-template-rows, grid-template-columns, and grid-template-areas together define the explicit grid of a grid container by specifying its explicit grid tracks.

    Simply put, the explicit grid consists of manually defined rows and columns.

    The size of the explicit grid is determined by the larger of the number of rows/columns defined by grid-template-areas and the number of rows/columns sized by grid-template-rows/grid-template-columns. Any rows/columns defined by grid-template-areas but not sized by grid-template-rows/grid-template-columns take their size from the grid-auto-rows/grid-auto-columns properties. If these properties don’t define any explicit tracks the explicit grid still contains one grid line in each axis.

    That last bit is what leads to line -1 being the same line as 1 because the explicit grid still contains one grid line in each axis.

    What is the implicit grid?

    As Manuel Matuzovic puts it:

    If there are more grid items than cells in the grid or when a grid item is placed outside of the explicit grid, the grid container automatically generates grid tracks by adding grid lines to the grid. The explicit grid together with these additional implicit tracks and lines forms the so called implicit grid.

    Conclusion

    Paraphrasing Jen Simmons:

    • -1 is the last line of the explicit grid
    • If you haven’t defined any explicit rows, then all your rows are implicit
    • For implicit rows, -1 is the same line as 1
    • Define explicit rows and grid-row: 1/-1 will work as expected

    Further Reading

  • Why Swiss Trains are the Best in Europe - YouTube

    I love this bit from the video where Jason quotes Enrique Peñalosa, the former mayor of Bogotá, Colombia:

    A developed country is not where the poor have cars. It’s where the rich use public transportation.

    But why is it important that wealthy people take public transportation? Because, as Jason mentions,

    […] for better or for worse, these people are likely to have the power and political influence to demand efficient service.

  • Crowdstruck (Windows Outage) - Computerphile - YouTube

    Dr. Steve Bagley explains in layman’s terms what an operating system is:

    […] Imagine the difference between a house and a hotel. If you own a house, you can decide how to use the rooms, what color to paint the walls. But if that house becomes a hotel, you might give people the option to change the air conditioning temperature, but you wouldn’t let them fit air conditioning into their room without permission from the building owner. And it’s a bit the same with a computer. The operating system is a bit like the people who run the hotel in that it’s controlling all the resources for the system. So if Microsoft Word crashes, these days it’s not going to take down your computer because the operating system is set up in such a way that it can access resources that have been assigned to it and clean that up, and everything else continues hunky-dory.

    And what happens if the operating system crashes and you get the blue screen of death (BSoD):

    At that point, the thing that’s in charge of controlling everything has gone wrong, is corrupted, and can no longer run. So there’s pretty much no option at that point other than to halt the machine, say something’s gone wrong, and let the user reboot and restart.

  • Blinded By the Light DOM – Eric’s Archived Thoughts

    Eric Meyer describes his journey of learning about and implementing fully-Light-DOM web components.

    You just take some normal HTML markup, wrap it with a custom element, and then write some JS to add capabilities which you can then style with regular CSS! Everything’s of the Light Side of the Web. No need to pierce the Vale of Shadows or whatever.

  • Adactio: Journal—HTML web components

    Jeremy Keith discusses what makes a custom element an HTML web component.

    If your custom element is empty, it’s not an HTML web component. But if you’re using a custom element to extend existing markup, that’s an HTML web component.

    React encouraged a mindset of replacement: “forgot [sic] what browsers can do; do everything in a React component instead, even if you’re reinventing the wheel.”

    HTML web components encourage a mindset of augmentation instead.

  • What questions to ask in an interview with a PM | Hindustan Times

    In this piece, Karan Thapar emphasizes that:

    • Interviewers must remember they are asking questions on behalf of the public.
    • Questions must be relevant, significant, and timely to demand accountability.
    • The interviewer must persistently push for answers instead of allowing monologues or tangents.
    • The interview should not serve as a platform to attack critics, but rather an occasion to make the PM respond to valid criticisms.
    • The interviewer and PM must interact as equals, with the former feeling empowered to challenge evasions or dubious claims.
  • Digging Into The Display Property: The Two Values Of Display — Smashing Magazine

    In Level 3 of the Display specification, the value of display is defined as two keywords. These keywords define the outer value of display, which will be inline or block and therefore define how the element behaves in the layout alongside other elements. They also define the inner value of the element — or how the direct children of that element behave.

    This means that when you say display: grid, what you are really saying is display: block grid. You are asking for a block level grid container. An element that will have all of the block attributes — you can give it height and width, margin and padding, and it will stretch to fill the container. The children of that container, however, have been given the inner value of grid so they become grid items. How those grid items behave is defined in the CSS Grid Specification: the display spec gives us a way to tell the browser that this is the layout method we want to use.

    As simply put by Rachel:

    When you define layout on a box in CSS, you are defining what happens to this box in terms of how it behaves in relation to all of the other boxes in the layout. You are also defining how the children of that box behave.

  • Transparent borders

    In web development, small design decisions can have a significant impact on accessibility and user experience. One such decision is how we handle borders on interactive elements.

    The problem with border: none

    When styling interactive elements like buttons, it’s common practice to remove default borders using border: none. However, this approach can lead to accessibility issues, especially in high contrast mode. As demonstrated in the image below, removing the border entirely can cause buttons to appear as floating text on the page, making it difficult for users with low vision to distinguish interactive elements.

    Side-by-side comparison of the contact form on Slae.app. The left image shows the contact form with forced colors disabled, displaying the default color scheme. The right image shows the contact form with forced colors enabled. In the right image, the submit button appears as floating text on the page.

    Dave Rupert explains the importance of the default border and why it exists:

    In the case of interactive form controls (inputs, textareas, buttons, etc.), those pesky borders were put there because they have an accessibility benefit when using High Contrast Mode, a feature used by 30.6% of low-vision users.

    The transparent border solution

    To address this issue, Dave recommends making the border or outline transparent instead of removing it entirely. This can be achieved with the following CSS:

    button {
    	border-color: transparent;
    }

    As demonstrated in the image below, this approach is effective for several reasons. First, sighted users will not notice the difference. Second, as Kilian Valkhof explains, in forced color mode, the border color or outline color “will be overwritten with the current text color, making it nicely visible again without needing any special adaption or re-styling for forced color mode.”

    Side-by-side comparison of the contact form on Slae.app with the transparent border solution applied. The left image shows the contact form with forced colors disabled, displaying the default color scheme. The right image shows the contact form with forced colors enabled. In the right image, the submit button appears as a button.

    User experience benefits

    Using transparent borders offers additional benefits for user experience. Consider hover effects, for example.

    button {
    	border: none;
    }
    
    button:hover {
    	border: 2px solid navy;
    }

    In such situations, applying a visible border on hover can inadvertently change the element’s dimensions. This change in size can result in a jarring visual effect.

    By setting a transparent border in the default state, we ensure smooth transitions and consistent element sizes across different states.

    <div>
    	<button class="no-border-btn">Button with no border</button>
    	<button class="transparent-border-btn">Button with transparent border</button>
    </div>
    .no-border-btn {
    	border: none;
    
    	&:hover {
    		border: 2px solid navy;
    	}
    }
    
    .transparent-border-btn {
    	border: 2px solid transparent;
    
    	&:hover {
    		border-color: navy;
    	}
    }

    Implications for design systems

    Transparent borders are also valuable in the context of themeable design systems. Brad Frost elaborates:

    When supporting multiple theme, it can be common for some themes to use borders while others don’t. This flexibility is great! Each brand is able to express themselves how they see fit. But if implemented using different border widths, shifts in the box model happen.

    By using border-color: transparent for themes without visible borders, designers and developers can maintain consistent element sizes across different variants and themes. This approach provides the flexibility to adapt the visual design while preserving the underlying structure and layout of the components.

    Conclusion

    Implementing transparent borders in your CSS addresses crucial accessibility concerns, enhances user experience across different display modes, and provides the flexibility needed for robust, adaptable design systems.