External Publication
Visit Post

The Hottest Box

Donnie D'Amato September 16, 2024
Source
Over the past year, I’ve had the task of creating layout components for an organization. This is something that was initially confused about. My initial assumption was that everyone knows about flexbox! It’s our lord and layout savior! Jokes about centering content should have vanished away now that we can use flexbox! Oh, how naïve I was. Realistically, the developer landscape doesn’t hone these skills well, and instead hides them behind APIs; even if those very APIs are identical to what a person would write in CSS. It’s true, people will do anything to avoid writing code in a file. Honestly, I stumbled all over making a robust layout component. The following is considerations I take into account and how I might build a new component if I was given another opportunity. Layout The first thing I’d take into consideration is layout using flexbox. I’m avoiding introducing grid configurations here. I’ve found that in the years I’ve been working with CSS, grid is the lesser used layout technique. It certainly has benefits over flexbox in many cases, but the majority of layout needs revolve around aligning items on a single axis in a container. Much of the confusion about flexbox comes from the alignment properties; and . They are very easy to get mixed up and, the results can be unexpected when you change the . I believe an improvement here would be to simplify the API. I’ll be using JSX syntax to describe the component API, but you could imagine similar configurations in your authoring experience of choice. The first thing I’d introduce is the boolean properties of and . The flag would switch between and so the container can fill its parent. The flag would toggle on so the children stack in a single column. I’d also include to align directly to . With that out of the way, now we need to address the alignment properties. Generally, the expectation for someone manipulating layout is to place the content in one of 9 locations within the container. For example, take the following CSS: This code will place the content in the top-right corner of an LTR container. But with one line of code, it’ll completely flip the position to the bottom-left corner: In my opinion, this is unexpected. The intention to show the items in a row versus a column shouldn’t have an effect on the alignment in this case. Instead, I’d like to see an approach where someone could configure the items such that the has no effect. I’m aware that there are cases where we want the above behavior, such as when the writing mode is adjusted. I’d argue that this is rare in comparison to the task of creating layouts. Furthermore, I’d like to lean into CSS Logical Properties, such that configuration inputs have aliases; / would transform to and / transforms to , of course allowing these values directly as well. I could imagine some flag that turns off (eg., ) this translation in cases where we want to force the direction regardless of the writing mode. Importantly, we’d need to inform what axis to apply the or . Logical properties describe that the horizontal axis is the “inline” direction, and the vertical axis is the “block” direction. As we have seen, when we update the , these axes flip where I’d argue this is largely unexpected. So instead of using and , I’d suggest and , similar to how and would be modernly applied. With this all in mind, we’d have the following: Regardless if the was applied or not, the children of this LTR container would be placed in the bottom-left corner. In an RTL container, the items would be placed in the bottom-right corner because defaults to . The final element to consider here is handling the concept of “self”. The flexbox ecosystem allows an item to essentially override the placement given by the parent through properties such as and . Knowing this, we can also see a potential problem with the current API. The words and aren’t clear as to what they are affecting. A better API naming convention would be more clear about what these are doing. That is why the flexbox APIs include the words and ; they are affecting the elements inside this container, not the container itself. This means that we should have similar but separate APIs for the concept of affecting the elements inside versus the element itself. We can communicate that layout is affecting the interior children with (ie., interior setup) and the exterior self with : We could also consider shorthands that handle these with a single value; affecting both and in the same way. The following would place the text horizontally and vertically within the box: means something slightly different in CSS compared to how it is being used here. In CSS, the “in” is speaking about how the target is being set inside a parent element. One more thing to mention is the more nuianced alignment properties, such as . Since we’re hiding implementation details to match some new expectations, I’d consider an option that would effectively override the given or (depending on the flag) to distribute the children. In this example, the would be set as instead of . I’m avoiding the word “space” here to not confuse with other spacing properties such as or which we’ll introduce later. Appearance By default, it makes sense to allow this container to be invisible when a configuration is omitted. This helps with general layout approaches, allowing boxes to be arranged without explicitly showing boundaries. However, in some cases we may want to have a box appear segregated from other boxes. Aligning with the idea of Mise en Mode, appearance properties would be informed by the use of intents (ie., strict semantic tokens) where we’d consider the priority that this box is meant to convey. So the box with the highest priority would be presented in a way that was clear to a user that they should pay attention here first before looking at other elements. This suggests that there is a setting that could either be numeric (, , , and so on) or Latinate ordinal numbers (, , etc.). I’d recommend the latter and having only , , and . This reduces the decision-making paralysis; making it more clear which to use. Having a number system of significant size makes it challenging to determine the most appropriate number. I also suggest using the term over including as if you need an additional level, you can include it later. As a sidenote, you should never assign the primary concept of anything as the default. Primary should be reserved as the main focus for the user. Meanwhile, your default should be set as the most common presentation of any element. If primary is your most common presentation, that means nothing is really important because everything is important. Continuing with the Mise en Mode concept, this allows any box to present itself with any color combination as provided by the current mode. This means, if you need a purple gradient to convey the supreme intelligence of AI, you can do it by informing the intents with new values, not by providing new tokens directly to a component. I believe the priority of any box is more closely tied to the concept of surfaces. We could imagine that the priority to be the base level of the page where most UI elements would live. Next, the level could be reserved for elements that are meant to appear on top of the UI but are contextual to some anchor. You can think of flyouts like context menus or tooltips. These are introduced because there is some more important information for you to take in before continuing, but they aren’t typically the most important thing to do. Finally, the level would be a full disruption like a modal, which is meant to appear on top of everything blocking further progress. Any one of these priorities would apply additional presentational styles to the element to allow it to convey the priority consistently. This is so our users can subconsciously learn the hierarchical order of the content and make better decisions. Spacing Continuing with Mise en Mode, more specifically its origins of Complementary Space, I believe we’ll only need two spacing options for box: and . These would be flags and not expecting values like T-shirt sizing. This is because the mode would inform the size. The in the second example indicates that a mode changes occurs here. This would affect all intents of this element and below new values. The value would refer to a mode that expects the density to shift down one level, such that and are smaller than if this mode wasn’t applied; as in the first example. You might consider simply adding as the option instead. I’m specifically using to indicate that this isn’t specific to but more related to Mise en Mode. If this element is meant to be the base of all other elements, then could be appropriate. If Complementary Space is too radical of an idea, feel free to wade in the depths of applying T-shirt sizing values. Loading Some work that was being done in parallel to the layout component was that of a skeleton loader. For many systems, this is a separate component than any others in the system for the specific purpose of displaying a placeholder while work is done in the background. This has the perception that the system is processing, as opposed to having a blank area waiting for content to appear. It was at this time that I realized that if the skeleton component represented content, and the box component was meant to arrange content, what if the box could represent placeholder content until it was provided? In other words, we can mark elements with an attribute that shows a skeleton loading presentation if the element has no content. Consider the following simple card layout: The flag would show a skeleton loading presentation to elements if no content is provided. That could be done with the CSS selector. Once content is added, the selector would no longer match and the skeleton styles would be removed through CSS. We could also consider being explicit about when the loader should be shown by using the value of . In a more complete system, there would exist and components that would have more specific enhancements that aligned better for , most likely inheriting from the foundational . For example, would have loading when no is provided (). would display skeleton lines instead of a single block, depending on the purpose of text. Titles could display a single line, while paragraphs could show 3. The purpose of embedding the ability to display a skeleton in any layout is powerful; assuming performance cannot be improved. This means that you can have a layout reused between the expected result and the lack of information with a single composition; just add content. No need to create a separate layout for when the content is missing and another for when the content is finally resolved. Semantics Something I’ve glossed over is how to assign the element that this component represents. In some systems, this is done with another prop that informs the HTML tag name to use (). Instead, I’d recommend trying a different approach. In this way, it is more clear that the part of the element is related to the element that will be rendered. Using could be more ambiguous to what the prop is meant to do, such as the word . You could also consider a more generic default export as that refers to a simple . Demo Here’s a demo of the concept, missing all the mode changing. See the Pen The Hottest Box by Donnie D’Amato (@fauxserious) on CodePen. EDIT (2024-09-26): Devon Govett recently posted a similar approach where a wrapper is added to any component in the system which will cause media and text elements inside to shimmer. Based on what I’ve written above, of course I really resonate with this. I like how the wrapping component is the trigger because you can also add accessibility attributes in there to markup the loading state within. There’s some feedback in the replies that challenges how the system is supposed to know what the content looks like. The fact is that we don’t need to know what the content looks like, we need to know what kind of content it is. This is why thinking about design as intention over aesthetics is the key to systems thinking and how we could support this approach. For example, the intention for a heading is commonly for introducing a short concept or label. Therefore, the loading presentation for the area where a heading should appear could always be displayed as a single block instead of considering several lines. Certainly, it is entirely possible that the final content does create multiple lines however, the purpose of the skeleton is not to match one-for-one with the incoming content. It is meant to indicate perceived progress using a loose blueprint of the expected content. We already know the styles for the text that will appear once the content comes through, including the font size. We can use that font size to set the minimum height of the skeleton placeholder, perhaps using the new unit. Also know that any styles that we use for the skeleton do not need to remain for when the content is applied. If the unit isn’t appropriate for the incoming font, then no need to set a minimum height when the element is . For paragraphs, you can pick a number of lines to display when we expect a paragraph. You could even be more considerate and wire in a container query that changes the number of lines based on the size of the paragraph. Wider paragraph containers larger than in width can display 2 lines, while smaller widths can display 3. This could imitate line wrapping for the same repeatable placeholder content. This way, a paragraph in a loading hero section would show 2 lines, while a more narrow card would show 3 lines. The easiest one of these content elements to consider is the image or really any media. Best practice for loading media is to set the dimensions in the HTML to help with content shifts which would clearly dictate the size of the container for the skeleton. In the event you couldn’t do this, you could have predetermined expectations for that media; square, 4:3, 16:9, and even a circle for avatars. These styles are already most likely applied to the media element already, so we shouldn’t need to use too much imagination about how this skeleton might look.

Discussion in the ATmosphere

Loading comments...