Manuel Matuzović - Blog

フィード

記事のアイキャッチ画像
Getting started with CSS Font Loading
Manuel Matuzović - Blog
I was in the mood to learn something new and so I decided to take a look at the CSS Font Loading API.My blog doesn't support comments yet, but you can reply via [email protected].
8年前
記事のアイキャッチ画像
I totally forgot about print style sheets
Manuel Matuzović - Blog
A small collection of useful CSS techniques and a quick reminder that print style sheets are still a thing. another old post (who cares?) that was originally on medium and now is on the author's domain blah blah-Random reply guy on Hacker NewsAaron Gustafson recently sent a tweet to Indiegogo in which he pointed out that their order details pages aren’t usable when printed.When I saw this tweet it struck me, because I realized that it has been a long time since I have optimized a page for print or even spared a thought on checking.Optimizing web pages for print is important because we want our sites to be as accessible as possible, no matter the medium. We shouldn’t make assumptions about our users and their behavior. People still print web pages. Just think about articles or blog posts, recipes, contact information, and directions or real estate sites. Someone somewhere will eventually try to print one of the pages you made.I gave up on home printers a long time ago because they alway
8年前
記事のアイキャッチ画像
Writing HTML with accessibility in mind
Manuel Matuzović - Blog
An introduction to web accessibility. Tips on how to improve your markup and provide users with more and betters ways to navigate and interact with your site.My blog doesn't support comments yet, but you can reply via [email protected].
7年前
記事のアイキャッチ画像
Writing JavaScript with accessibility in mind
Manuel Matuzović - Blog
Tips on how to improve the accessibility of your JavaScript components and provide users with more and better ways to interact with your website or web app.My blog doesn't support comments yet, but you can reply via [email protected].
7年前
記事のアイキャッチ画像
A Collection of Interesting Facts about CSS Grid Layout
Manuel Matuzović - Blog
A few weeks ago I held a CSS Grid Layout workshop. Since I'm, like most of us, also pretty new to the topic, I learned a lot while preparing the slides and demos.I decided to share some of the stuff that was particularly interesting to me, with you.My blog doesn't support comments yet, but you can reply via [email protected].
7年前
記事のアイキャッチ画像
Progressively Enhancing CSS Layout: From Floats To Flexbox To Grid
Manuel Matuzović - Blog
When can I start using CSS grid layout?” “Too bad that it’ll take some more years before we can use grid in production.” “Do I need Modernizr in order to make websites with CSS grid layout?” “If I wanted to use grid today, I’d have to build two to three versions of my website.” The CSS grid layout module is one of the most exciting developments since responsive design. We should try to get the best out of it as soon as possible, if it makes sense for us and our projects.My blog doesn't support comments yet, but you can reply via [email protected].
7年前
記事のアイキャッチ画像
The Difference Between Explicit and Implicit Grids
Manuel Matuzović - Blog
Grid Layout finally gives us the ability to define grids in CSS and place items into grid cells. This on its own is great, but the fact that we don't have to specify each track and we don't have to place every item manually makes the new module even better. Grids are flexible enough to adapt to their items.This is all handled by the so called explicit and implicit grid.My blog doesn't support comments yet, but you can reply via [email protected].
7年前
記事のアイキャッチ画像
Writing CSS with Accessibility in Mind
Manuel Matuzović - Blog
About a year ago I started to focus more on web accessibility. The most effective method of learning for me is teaching others. That’s one of the reasons why I’m talking at meetups and conferences and why I’m writing articles about the topic. I wrote about Progressive Enhancement for Smashing Magazine and about accessibility basics here on Medium. This article is the third in a series of collections of accessibility tips. They’re in no particular order, you can read Writing HTML with accessibility in mind and Writing JavaScript with accessibility in mind now or later if you’re interested.My blog doesn't support comments yet, but you can reply via [email protected].
7年前
記事のアイキャッチ画像
My Accessibility Journey: What I’ve Learned So Far
Manuel Matuzović - Blog
Last year I gave a talk about CSS and accessibility at the stahlstadt.js meetup in Linz, Austria. Afterward, an attendee asked why I was interested in accessibility: Did I or someone in my life have a disability?I’m used to answering this question—to which the answer is no—because I get it all the time. A lot of people seem to assume that a personal connection is the only reason someone would care about accessibility.My blog doesn't support comments yet, but you can reply via [email protected].
6年前
記事のアイキャッチ画像
Another Collection of Interesting Facts about CSS Grid Layout
Manuel Matuzović - Blog
Last year, I assembled A Collection of Interesting Facts about CSS Grid Layout after giving a workshop. This year, I worked on another workshop and I've learned some more exciting facts about the layout spec we all so love.Of course, I'm not going to keep my knowledge to myself. I'm happy to share my findings once again with you, the CSS-Tricks community.My blog doesn't support comments yet, but you can reply via [email protected].
6年前
記事のアイキャッチ画像
I Threw Away my Mouse
Manuel Matuzović - Blog
Last year I attended JS Conf Budapest and I watched many great talks but “YES! Your site can (and should) be accessible” by Laura Carvajal was the most thought-provoking talk for me. Laura explained how the Financial Times made accessibility a core part of their development process and she shared several lessons she and her team had learned. In her third lesson Throw away your mouse, Laura mentioned that just testing with the keyboard wasn’t enough and that only going keyboard-only all the time made a difference.My blog doesn't support comments yet, but you can reply via [email protected].
5年前
記事のアイキャッチ画像
Hello World!
Manuel Matuzović - Blog
It happened. I finally have a website.Of course, it's not my first website but the first one in a long time. My very first personal site went online about 17 years ago. It was a table-based layout with no CSS at all. All styling happened by adding HTML attributes.<font face="arial" size="4"> <table border="2" cellspacing="2" cellpadding="0" width="550" bordercolor="#000000" bgcolor="#004600" > ... </table></font>It was online for about 2 years. After that, the only thing I did was to change the under construction graphic periodically. As it turns out, I'm really bad at getting things done.Fast forward 10 years, I was at my second conference ever, at Smashing Conf Freiburg 2014. I was so inspired by the great talks I had seen, that I decided to set up a WordPress-based blog in one of the breaks to share my notes. The theme was slow and the design was boring but I had a website, which was great because I had the chance to share my knowledge.Again, I lost interest after 2 years because I
5年前
記事のアイキャッチ画像
The Dark Side of the Grid (Part 1)
Manuel Matuzović - Blog
CSS Grid Layout is one of the most exciting recent CSS specifications because of its flexibility, extent, and power. It makes our lives so much easier but it also creates new dangers regarding user experience and accessibility.PrefaceIt has already been two years since the first browsers, Chromium 57 and Firefox 52, shipped CSS Grid Layout un-prefixed. Many developers have experimented with it or are using it in production already. More will come as soon as support for Internet Explorer 10 and 11 becomes less important.\This series of articles will give you an overview of potential implementation pitfalls, or in other words, the dark side of the grid. OverviewWhat’s CSS Grid Layout? (in this article)Name and theme of this article (in this article)Pink Floyd Fun Fact 1 (in this article)Compromising on Semantics (in this article)Pink Floyd Fun Fact 2 (in part 2)Changing Visual Order (in part 2)Cross Browser SupportPink Floyd Fun Fact 3Whose responsibility is it?Pink Floyd Fun Fact 4What’
5年前
記事のアイキャッチ画像
Improving the keyboard accessibility of Embedded CodePens
Manuel Matuzović - Blog
I'm a huge fan of CodePen (No, they didn’t pay me to write this). I'm using it for prototyping, experimenting, sharing code, and in my latest blog post, The Dark Side of the Grid, I'm also making use of their Embedded Pens.CodePen allows you to customize syntax highlighting, and background and text colors of UI elements in Embedded Pens. CodePen Embed Theme BuilderAccessibility winsBefore I tell you where I see room for improvement, I want to highlight what they did well.You can customize colors and make sure that contrast ratios are high enough.There’s a click-to-load option. Pens can be in a preview state where they need to be clicked to loaded, which is good for performance.All buttons and links in Pens are HTML <button> and <a> elements with actual text (What a time we live in that this makes me happy).Embedded Pens are iframes. There’s a title attribute on each iframe with the title of the Pen as a value. This is important because screen readers announce this value when the iframe
5年前
記事のアイキャッチ画像
12 Tips for More Accessible React Apps (Slides, React Finland 2019)
Manuel Matuzović - Blog
If you want to improve the accessibility of your React apps but you don't know how or where to start, this talk is just what you need. Manuel shares 12 tips that will help you build web sites and applications that can be used by anyone. Each tip fits on one slide and you'll be able to put them into practice right away without having to learn anything fundamentally new. The tips include testing, HTML, JS techniques, and general best practices.Recording of the talkSlidesThe slides are online on this page slide by slide with descriptions.IntroductionHello React Finland!About meMy name is Manuel Matuzovic, I'm a frontend developer from Vienna.Link to the SlidesThe slides for this talk are already online if you want to follow along on your laptop.I'm not a React developer but I know how awesome React is. Today I'm here to give you tips that will help you create better apps and reach more people.About this talkThis talk is called 12 Tips For More Accessible React Apps. At the time when I pic
5年前
記事のアイキャッチ画像
The Dark Side of the Grid (Part 2)
Manuel Matuzović - Blog
CSS Grid layout is powerful and flexible. It's great for our development experience, but it may come at the cost of user experience and accessibility if we don’t use it responsibly.This article series gives you an overview of potential implementation pitfalls; or, in other words, the dark side of the grid.document.querySelector('main').classList.add('dark') OverviewWhat’s CSS Grid Layout? (in part 1)Name and theme of this article (in part 1)Pink Floyd Fun Fact 1 (in part 1)Compromising on Semantics (in part 1)Pink Floyd Fun Fact 2 (in this article)Changing Visual Order (in this article)Cross Browser SupportPink Floyd Fun Fact 3Whose responsibility is it?Pink Floyd Fun Fact 4Changing Visual OrderIn part 1, I addressed the issue with flattening document structures. Before we talk about changing visual order, let me enlighten you with more Pink Floyd wisdom.Pink Floyd Fun Fact #2In 1975, Pink Floyd helped to finance the movie Monty Python and the Holy Grail by the comedy group Monty Pytho
5年前
記事のアイキャッチ画像
Building the most inaccessible site possible with a perfect Lighthouse score
Manuel Matuzović - Blog
It’s always nice to see when people post their Lighthouse scores on social media to highlight how well they’ve optimised their own or their client's website. It shows that they care about the quality of what they build..lighthouse-test { position: relative;}.lighthouse-test button { position: absolute; z-index: 111; left: 0; right: 0; top: 0; bottom: 0; margin: auto; max-height: 5.3rem;}.lighthouse-test img { opacity: 0; transition: opacity 0.3s; }.lighthouse-test .content__image-wrapper::before,.lighthouse-test .content__image-wrapper::after { display: none; }.lighthouse-test--finished button { display: none;}.lighthouse-test--finished img { opacity: 1;}Lighthouse awards us with the number 100 in a green circle if we did an exceptional job. It’s something you can proudly share with your client or on Twitter.It’s important to measure the quality of our code, but it’s even more important that we interpret the scores automatic testing tools give us correctly. If Lighthouse tells us that
5年前
記事のアイキャッチ画像
Don't be afraid to share
Manuel Matuzović - Blog
I don’t consider myself a web accessibility expert but I’ve learned enough in a relatively short time to feel comfortable enough to share my knowledge in blog posts, workshops and talks. Here’s some advice, if you want to share stuff but are wary about doing it.1. Find something that interests you and stick to it.Fullstack is bullshit and so is trying to be an expert in everything. Pick that one thing that interests you the most (design, js, css, a11y, ux,…) and try to be really good in that specific area.(PS: it can change over time)2. Read, read a lot.Find experts in the area that interests you and subscribe to their blogs and follow them on social media. Read as many articles as you can. If you can afford it, buy books or videos. If not, ask the author if they’ve got promo codes for you (some do that).3. Share!I learn the most by explaining stuff to others. If you want to learn something, write an article about it or give a talk at a meetup. You can do that even if you’re not an “ex
5年前
記事のアイキャッチ画像
Please write and talk more about CSS
Manuel Matuzović - Blog
I saw a lot of JavaScript today considering that I was at a CSS conference.It absolutely makes sense because for many people writing CSS means writing JS but I've seen enough pro/con talks about CSS-in-JS.I do enjoy talks that are more advanced and show how to optimize the CSS people write in JS but I'd really love to see a CSS only talk or read an article again that challenges the way I write CSS or approach layout and architecture.I have a feeling that we should talk and write more about CSS, advanced CSS. Tutorials have their place but I'd love to read and hear more about concepts and approaches, layout and architecture. I know that @rachelandrew, @heydonworks and @hankchizl are doing a lot but I believe there’s more that can be discussed and shared. :)My blog doesn't support comments yet, but you can reply via [email protected].
5年前
記事のアイキャッチ画像
Beyond automatic accessibility testing: 6 things I check on every website I build
Manuel Matuzović - Blog
I just finished an accessibility audit for a client and I decided to share some quick checks I perform in every site I audit and build. It’s something that you can apply to your project right away, you don’t have to learn a tool or a software.Step 0: Automatic testsThe first thing I do is run accessibility checks in Lighthouse to figure out if anything obvious is wrong. Automatic accessibility tests are great but they only check a subset of what needs to be tested. If you have a score of 100 or 0 errors, you’re not done. It just means you’ve laid the groundwork for manual testing.Step 1: Check image descriptionsThe first semi-manual test I perform is check if images have descriptions and if they’re described correctly. I’m using a browser extension called Web Developer for that. You can highlight images that have no alt attribute or display the value of alt attributes next to images.Step 2: Disable all stylesAnother feature of the Web Developer extension is the ability to disable CSS o
5年前
記事のアイキャッチ画像
matuzo.at from scratch #0 - introduction
Manuel Matuzović - Blog
I'm redesigning and building my website from scratch. In this first video I introduce myself and I describe what my plans are for the following weeks and months. Watch it to see if this series of videos is for you or not. In this pageVideoTranscriptVideoTranscript[Introduction]Hello and welcome to this first video in a series of videos where I'm going to redesign and build my website from scratch.My name is Manuel Matuzović, I'm a front-end developer from Vienna and I like sharing stuff. I usually do it on my website matuzo.at. Matuzo is my nickname and at is the top-level domain for Austria. I write articles about CSS and accessibility and sometimes I also publish on other websites where write about the same topics.[Showing articles I've published on Smashing Magazine, CSS-Tricks and A List ApartI also like to give talks at meetups and conferences, and now I decided to share on another medium, which is video.I already have a website and I want to redesign it for different reasons.The
4年前
記事のアイキャッチ画像
Bad accessibility equals bad quality
Manuel Matuzović - Blog
When I talk about web accessibility at meet-ups and conferences, it’s safe to assume that at least one person will ask me something like “Yeah, accessibility sounds nice, but how many people are actually disabled? How many of my users are blind? And why would a blind person visit my website?”1. Who gives a fuck?!We’re not building websites for ourselves or our stakeholders, we’re building them for our users, for actual human beings. It’s our job to enable as many people as possible to use what we build. Everything else makes little sense. There’s no point in building something that can’t be used. Stop making assumptions about your audience and start building inclusive products.2. It's not just about disabilitiesWeb accessibility is not just about keyboard users, color contrast or screen readers. Accessibility is a perfect indicator for the quality of a website. Accessibility is strongly interlocked with other areas of web design and web development. If your website is accessible, it us
4年前
記事のアイキャッチ画像
matuzo.at from scratch #1 - Designing and finding inspiration
Manuel Matuzović - Blog
The this video I explain how I approach design and how I find inspiration, both online and offline. Subscribe to the YouTube channel. In this pageVideoTranscript IntroRequired skills you'll needHow I approach designFinding inspirationOutroVideoTranscript[Introduction]Hi!YouTube channel. I started with 5 subscribers and now I have 102, which is really really amazing.In my first video I talked about my plans for the next couple of weeks, the technology I'm going to use and what I'm going to cover and what I want to implement. One thing I didn’t tell you about – and thank you Bernd for pointing this out – is the required skill level that you will need in order to be able to follow me.[Required skills you'll need]If you are completely new to eleventy, it's absolutely fine. I'm doing a lot of research right now, I'm looking at other websites and I'm trying to steal all the great ideas so they can find their way into my website, and I'm going to start from zero and explain everything that I'
4年前
記事のアイキャッチ画像
CSS pro tip for mac users: always show scroll bars in macOS.
Manuel Matuzović - Blog
I built a quite complicated component in HTML and CSS last week and I was happy with the result. After testing in different browsers and operating systems, I realised that I had to rewrite the whole thing because I didn’t consider that by default scroll bars don’t take up space on macOS, but on Windows they do.tweeted about a similar issue about a year ago, but it seems that I didn’t take my own advice, so here’s a reminder for you and me.Change your macOS settings to always show scroll bars. This will help you spot overflow bugs, e.g. caused by width: 100vw, before anybody else does. :)Side note: Adding max-width: 100% often helps..header { width: 100vw; max-width: 100%;}My blog doesn't support comments yet, but you can reply via [email protected].
4年前
記事のアイキャッチ画像
Here’s what I didn’t know about list-style-type
Manuel Matuzović - Blog
At the CSS-in-Vienna meet-up last week Ulrich told me that starting with Chrome 79 it's possible to define a string value for the list-style-type property. I was surprised because I thought ::marker was supposed to solve that. That's why I did some research, here’s what I learned.list-style-type accepts a string valueIn Chrome 79+, Firefox 39+, and Opera 66+ it's possible to define a string value as the bullet of an ordered or unordered list, which means that emojis work, as well.ul { list-style-type: '🐣';}Item 1Item 2The list item may also be described as an Unicode value.ul { list-style-type: '\1F44D';}Item 1Item 2@counter-style is a thingBrowsing the MDN page for list-style-type I discovered that there’s a @counter-style at-rule. It allows you to define custom counter styles. It's list-style-type with super powers.Currently, only supported in Firefox, there are several interesting options, like a list of one or multiple symbols, suffix, prefix or range. I won’t describe them here, ...
4年前
記事のアイキャッチ画像
Here’s what I didn’t know about…
Manuel Matuzović - Blog
Recently, it feels like I see a property, a property value or a selector I haven’t heard about pop up every day. Often these things I learn aren’t even that new, which makes me wonder how much I don’t know about CSS.In this series of articles I’m (re)visiting CSS properties and selectors, trying to find out what I didn’t know about them.Here’s what I didn’t about…contentcolorlist-style-type:whereMy blog doesn't support comments yet, but you can reply via [email protected].
4年前
記事のアイキャッチ画像
Reading recommendations: Animation on the web and vestibular disorders
Manuel Matuzović - Blog
It’s 7:25 a.m. and I’ve already learned so much. Actually, I just wanted to write a few paragraphs for an article about accessibility in CSS before I go to work, but I got caught up reading about animation on the web and vestibular disorders.The articles I read written by Eric W. Bailey and Shell Little, Val Head, and Facundo Corradini are so great that I just had to dedicate this post to them.Designing Safer Web Animation For Motion SensitivityVal describes how we can make animated movements easier on folks who find it triggering.Read Designing Safer Web Animation on A List Apart.Revisiting prefers-reduced-motion, the reduced motion media queryEric highlights the importance of a thoughtful use of animation on the web and he raises awareness for the prefers-reduced-motion media query. Shell explains the relation between animation and neurodivergence.Read Revisiting prefers-reduced-motion on CSS-Tricks.Accessibility for Vestibular Disorders: How My Temporary Disability Changed My Perspe
4年前
記事のアイキャッチ画像
One of my favourite accessibility testing tools: The Tab Key.
Manuel Matuzović - Blog
I’ve been employed for about a year now and many things are different compared to being a freelancer. One interesting thing in my specific situation is that I have to evaluate the accessibility of third-party tools regularly. Usually there’s no time for a full audit, I have to gain a good overview of the quality of a product as quickly as possible.This article is available in German: Eines meiner Lieblingswerkzeuge für Barrierefreiheit-Checks: Die Tabulatortaste.I’ve already shared 6 things I check on every website I build, but this time I want to focus on one of the most powerful testing tools: The Tab key.Let’s say, you’ve managed to score 100 on the Lighthouse accessibility audit. This doesn’t necessarily mean that your site is accessible, you’ve just laid the groundwork for the actual testing. A next step could be putting your mouse away and using the keyboard only to navigate your site.Here’s what pressing the Tab key will tell you about your website:1. Focus stylesIf you press th
4年前
記事のアイキャッチ画像
Eines meiner Lieblingswerkzeuge für Barrierefreiheit-Checks: Die Tabulator-Taste.
Manuel Matuzović - Blog
Ich bin seit etwa einem Jahr angestellt und viele Dinge sind anders als bei meiner freiberuflichen Tätigkeit zuvor. Eine interessante Neuerung ist, dass ich regelmäßig die Zugänglichkeit von Tools Dritter bewerten muss. Dabei bleibt normalerweise keine Zeit für eine vollständige Prüfung, ich muss mir so schnell wie möglich einen guten Überblick über die Qualität eines Produkts verschaffen können.Hinweis: Das ist eine Übersetzung des englischsprachigen Originals: “One of my favourite accessibility testing tools: The Tab Key.”.Ich habe bereits 6 Dinge geteilt, die ich bei jeder von mir erstellten Website überprüfe, aber jetzt möchte ich mich auf eines der effektivsten Prüfwerkzeuge konzentrieren: Die Tabulator-Taste.Nehmen wir an, du hast es geschafft, beim Lighthouse Accessibility Audit 100 Punkte zu erreichen. Das bedeutet nicht unbedingt, dass deine Website barrierefrei ist, du hast nur den Grundstein für die eigentlichen Tests gelegt. Ein nächster Schritt könnte darin bestehen, die M
4年前
記事のアイキャッチ画像
Why 543 KB keep me up at night
Manuel Matuzović - Blog
The question how good good enough is and at which point a website is ready to go online is keeping me busy lately. The web is in bad shape and it’s because we’re making it too easy on ourselves. “It’s online and works in most browsers” is not enough - we have to be much more considerate of what we’re putting online.Some background: About three years ago I specialized in web accessibility. Now it’s not just my job to make sure that the websites I build are accessible, but the websites of others, too. I’m a front-end developer, but also a consultant and auditor. I’m employed for about a year now as well, and I have to evaluate a lot more third party web products than I used to.Something has changedA friend recently sent me the link to a website and asked me for feedback, because I had experience with the content management system their client was using.checked a few things and then browsed through the website with Dev Tools and the network panel open. The homepage had a page weight of 4.
4年前
記事のアイキャッチ画像
How many browsers do you know?
Manuel Matuzović - Blog
While testing a new feature recently, I realised that I don’t know too many browsers. I can list some, but I don‘t really know them like I know Firefox or Chrome. I want to change that, and I invite you to do the same.Firefox Developer Tools have improved so much in the last few years that I naturally switched from Chrome as my main development browser to Firefox. This helped me understand their differences, not just when working (developer experience) but also when surfing (user experience). I’m not well organised I use them only for testing and then I forget about them.How many browsers do you know by heart?Okay, try to list as many browsers as possible. I’ll give you a few seconds.…Here’s my list: Chrome, Chrome for Android, Firefox, Firefox Mobile, Opera, Opera Mobile, Opera Mini, Vivaldi, IE, Edge, Brave, UC, Firefox Focus, Safari, Samsung Internet, Firefox DE, Safari iOS.Did you know that there’s a DuckDuckGo Browser, a browser called Mint with over 5 Million downloads in the And
4年前
記事のアイキャッチ画像
Here’s what I didn’t know about “color”
Manuel Matuzović - Blog
This is part 2 of my series Here’s what I didn’t know about… in which I try to learn new things about CSS. This time I'm trying to find out what I didn’t know about the color property.When setting the CSS color property, 2 things happen.The foreground color value of an element's text changes.The currentcolor value changes.a { color: #237680;}circle { fill: currentColor;}<a href="#"> Hello World! <svg height="30" width="30" focusable="false"> <circle cx="15" cy="15" r="10" fill="red"> </svg></a> currentColor is the default color value of some propertiesUsually when I work with the border property, I change the width and color of the border. That’s probably why I’ve never noticed that the default value of border-color is currentColor..parent { color: #ca3041; border-style: solid;}<div class="parent">yo!</div>yo!So, if you change the color value of an element, its border color changes, too.That’s the case for most properties that have a color.text-emphasis-color.parent em { text-emphasis-
4年前
記事のアイキャッチ画像
Blogging is one of the best ways of learning
Manuel Matuzović - Blog
I can’t stress enough how important it is to blog if you want to become better at web development. You learn so much more by explaining something in your own words than by just reading and copying & pasting.I overcame my fear of writing and speaking, because I realized that…It doesn’t matter if someone else has written about the same topic. Different perspectives are important.You don’t have to create cool demos or present smart hacks. Most people are looking for actionable advice, not next level shit or eye candy.It doesn’t matter how many people read your blog. Someone somewhere will be glad you wrote that article.Talk about what interests you, not about what you believe others will like. Most of my talks and articles are about “basic” HTML and CSS, because that's what I like.Don’t be afraid to write/speak in a foreign language. I speak English with a strong accent and there are probably many mistakes in this tweet alone, but guess what, most people don’t care. My English isn’t perfe
4年前
記事のアイキャッチ画像
The beauty of progressive enhancement
Manuel Matuzović - Blog
Nokia released an updated version of its iconic Nokia 3310 about 3 years ago. It was affordable for me (€60/$65), so I had to get one. It came with a 2 MP camera, a battery that lasts 30 days (up to 22 hours talk time), 2G, 16 MB storage, the original Snake game, and a browser.Screenshot: Nokia.Opera MiniYou can access the worldwide web on the Nokia 3310 with Opera Mini. There are different versions of the Opera Mini browser, how it renders pages depends on the operating system, device, and settings you’re using.Some other notable things about JavaScript in Opera Mini:All scripts are allowed a maximum of two seconds to execute.setInterval and setTimeout functions are disabled.The number of events allowed to trigger scripts is limited.Opera Mini has a strong focus on performance and data saving. I guess that’s also one reason why it’s installed on my Nokia phone. Now, the browser installed on my 3310 is different to the Opera Mini version on my smartphone. It’s the one that’s usually pr
4年前
記事のアイキャッチ画像
Here’s what I didn’t know about “content”
Manuel Matuzović - Blog
This is part 3 of my series Here’s what I didn’t know about… in which I try to learn new things about CSS. This time I'm trying to find out what I didn’t know about the content property.A few weeks ago Stefan published a post on his website called “The CSS "content" property accepts alternative text”, which blew my mind. He showed that the content property excepts 2 values and not just 1, the actual content and an alternative text..new-item::before { /* "Highlighted item" and element content is read out */ content: '★' / 'Highlighted item';}I didn’t know that and I was wondering if there were more things I didn’t know about the content property. Since you’re reading this, I found something, so let’s see what I was able to add to my “Here’s what I didn’t know about…” series.How I’m using the content attribute.Before I started my research, I was using this property primarily for 3 things.Adding an element to another element using pseudo elementsIf I want to create a simple shape in CSS t
4年前
記事のアイキャッチ画像
Reverse ordered lists
Manuel Matuzović - Blog
I’m working on a project where I have a list of items in reverse order. The list starts with the latest item and ends with the oldest. I wanted to express that both semantically and visually. I did some research and found interesting solutions, some of them good, others not so much.The result should look a little like this.3. CLet’s check out our options.The reversed attribute in HTMLThe easiest and most straightforward solution is the reversed attribute in HTML.<ol reversed> <li>C</li> <li>B</li> <li>A</li></ol>C B AIt reverses the order of the list marker semantically and visually; the list starts with 3. and ends with 1., and screen readers announce the list in DOM order together with the correct number. “3 C 2 B 1 A”That’s how you do it, you can stop reading here, if you don’t need custom styling and it doesn’t bother you that the reversed attribute is not supported in IE and old implementations of Edge.The value attribute in HTMLAnother approach, which yields the same result, is u
4年前
記事のアイキャッチ画像
Accessible to some
Manuel Matuzović - Blog
According to WebAims annual accessibility analysis, 98.1% of home pages of the top 1,000,000 websites have detectable WCAG 2.0 failures. Some of these sites may only have minor contrast issues or maybe just a single missing id, while others are highly inaccessible. However, this number is pretty damn high, considering the fact that automatic testing tools only report obvious accessibility issues.Only 1.9% of the tested home pages pass automatic testing, which is fine, but it doesn’t mean that there aren’t any barriers on these websites either. True accessibility extends beyond automated tests and WCAG regulations.It's fair to say that most websites are only accessible to some.98.1% sounds bad, but for most of us it’s just a number, isn’t it? For me, as someone whose job it is to help others build accessible websites, it’s easier to imagine what the real-life effects of these failures can be. To help you get a better understanding of what this high percentage means for users and their d
4年前
記事のアイキャッチ画像
Writing even more CSS with Accessibility in Mind, Part 1: Progressive Enhancement
Manuel Matuzović - Blog
About 4 years ago, I began to focus on web accessibility professionally. I read many articles and books, watched talks, followed experts, and I also shared my knowledge at meet-ups and online. The first 3 articles I wrote were Writing HTML with Accessibility in Mind, Writing JavaScript with Accessibility in Mind, and Writing CSS with Accessibility in Mind. I've shared the most exciting new things I've learned about creating inclusive experiences in each language.I wrote Writing CSS with Accessibility in Mind in 2017 and I’ve covered topics like font size, line height, print style sheets, hiding content, contrast, DOM order vs. visual order and focus styles. 3 years have passed, CSS has evolved, and I’ve learned new things. Therefore, I’ve decided to write about even more CSS with accessibility in mind.In this seriesThis series of articles covers 4 major topics:Progressive enhancement (this article)User preferences (coming soon)CSS and semantics (coming soon)Improving accessibility with
4年前
記事のアイキャッチ画像
Writing even more CSS with Accessibility in Mind, Part 2: Respecting user preferences
Manuel Matuzović - Blog
In the first article of this series, I explained how important progressive enhancement is for web accessibility. Building websites layer by layer allows for a cleaner separation of concerns and more resilient experiences. This second article is about user preferences and how to respect them when writing CSS.In this seriesThis series of articles covers 4 major topics:Progressive enhancementUser preferences (this article)CSS and semantics (coming soon)Improving accessibility with CSS (coming soon)Respecting user preferencesOperating systems and browsers provide users with options to customize their browsing experience, and it’s our job to respect these preferences in our style sheets. In the following chapter, I’ll give you examples of how we can build designs according to our ideas while still respecting user preferences.Font sizeA fundamental thing we should do is respect our users’ preferred font size for running text.Base font sizeThe default font size in most browsers is 16px but it
4年前
記事のアイキャッチ画像
The lang attribute: browsers telling lies, telling sweet little lies
Manuel Matuzović - Blog
The lang attribute is an essential component in the basic structure of an HTML document. It’s important that we define it correctly because it affects many aspects of user experience. Unfortunately, the negative effects a missing or wrong attribute can have aren’t always evident. Austrian news site orf.at learned that the hard way recently.Applied to the <html> element, the lang attribute defines the natural language of a page. If your document is written in French, you would set it to fr.<html lang="fr"> <head> … </head> <body> … </body></html>Search engines, screen readers, browser extensions, and other software use this information.Why is the lang attribute so important?Adrian Roselli wrote about the Use of the Lang Attribute, so I will not repeat everything he says but I’ll give you some examples of how this attribute influences UX, and I will show you what happened recently on the most popular Austrian website in Austria.Auto-translationTranslation tools like Google Translate may
4年前
記事のアイキャッチ画像
Slow Movement
Manuel Matuzović - Blog
My answer to the question “What is one thing you learned about building websites this year?”My blog doesn't support comments yet, but you can reply via [email protected].
3年前
記事のアイキャッチ画像
Ordering CSS properties
Manuel Matuzović - Blog
I haven’t thought about ordering CSS properties in a while, but I began to work on the redesign of HTMHell recently and I decided to challenge my current approach.How I’m ordering CSS properties nowHonestly, I don’t know. It’s a mix of logical grouping, alphabetical order and just no order at all. It kinda has some structure, but I guess you could describe it as pretty arbitrary.Here’s a random class from the current HTMHell website..site-intro { font-size: 2rem; text-align: center; font-weight: 700; line-height: 1.5; max-width: 36ch; margin-left: auto; margin-right: auto;}According to a poll I ran on Twitter, most people order by type, closely followed by alphabetical ordering. I also did a quick search and, as expected, many people have thought and written about different approaches and the pros and cons compared to others.Poll Results: How do you order your CSS properties?“Outside In” — Ordering CSS Properties by ImportanceHow to organize CSS @ 9elementsAlphabetize your CSS properti
3年前
記事のアイキャッチ画像
More or less burger-less navigation
Manuel Matuzović - Blog
For your and my inspiration: A collection of websites that don’t hide the navigation on mobile behind a burger/menu button. Show some, hide the restSingle row, centeredSingle row, space-betweenSingle row, scrollableMultiple rowsVertical navigationSingle row, additional iconsMultiple rows, aligned to the rightMy blog doesn't support comments yet, but you can reply via [email protected].
3年前
記事のアイキャッチ画像
Dev Tools: Debugging DOM Tree modifications
Manuel Matuzović - Blog
“Break on Subtree Modification” allows you to debug dynamically added and removed DOM nodes.The other day I was debugging a Drag’n’Drop component, and I noticed that it added a DOM node every time I dragged an element. I wanted to inspect the node and see what’s going on in the CSS panel, but as soon as I dropped the element I was dragging, the new node was removed from the DOM (Document Object Model). I tried to catch it quickly, but I didn’t have a chance.Break StuffA quick search pointed me to an option I’ve noticed several times in the context menu of nodes in the elements panel, but I never cared to see what it was doing: “Break on…”.Selecting “Break on Subtree Modification” pauses any script that modifies the DOM of the selected element and jumps to the line in the script that modified it.Now that the script is paused, you can unhurriedly inspect the DOM.This option helped me not only to debug the component, but I also felt less stupid because I didn’t have to desperately try to
3年前
記事のアイキャッチ画像
Highlighting columns in HTML tables
Manuel Matuzović - Blog
The col element allows us to style columns in tables.In the past, I’ve used the colgroup and col elements to define max-widths for columns in tables when I didn’t want to rely on the default algorithm for distribution of widths, usually when building templates for e-mail newsletters.A simple table with dummy content<table> <thead> <tr> <th>First column</th> <th>Second column</th> <th>Third column</th> </tr> </thead> <tbody> <tr> <td>First cell</td> <td>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Id, dolor delectus. Modi accusamus id magni.</td> <td>Last cell</td> </tr> </tbody></table>First column Second column Third column First cell Lorem, ipsum dolor sit amet consectetur adipisicing elit. Id, dolor delectus. Modi accusamus id magni. Last cell A simple table with dummy content and a fixed width for the first and last column<table> <colgroup> <col style="width: 150px"> <col> <col style="width: 150px"> </colgroup> <thead> …</table>First column Second column Third column F
3年前
記事のアイキャッチ画像
My current HTML boilerplate
Manuel Matuzović - Blog
Every element I use for the basic structure of a HTML document, with explanations why.Traducción a Español by www.ibidemgroup.com.Usually when I start a new project, I either copy the HTML structure of the last site I built or I head over to HTML5 Boilerplate and copy their boilerplate. Recently I didn’t start a new project, but I had to document the structure we use at work for the sites we build. So, simply copying and pasting wasn’t an option, I had to understand the choices that have been made. Since I spent quite some time researching and putting the structure together, I decided to share it with you.Cool, this is like https://github.com/h5bp/html5-boilerplate but a little worse.-Random reply guy on Hacker NewsMy boilerplateThis is the final document. Scroll down for details.<!DOCTYPE html><html lang="en" class="no-js"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Unique page title - My Site</title> <script type="module">
3年前
記事のアイキャッチ画像
Browser support: focus pseudo classes
Manuel Matuzović - Blog
I don’t know who needs to hear this, but that’s the current browser support for :focus-visible and :focus-within, and I love it!:focus-visible browser support:focus-within browser supportMy blog doesn't support comments yet, but you can reply via [email protected].
3年前
記事のアイキャッチ画像
Element diversity
Manuel Matuzović - Blog
Did you know that there are 112 elements in HTML?!<div id="appRoot"> <div> <div> <div> <div class="heading">Heading</div> <div class="content"> <div> <div> <div class="list"> <div></div> <div></div> <div></div> </div> </div> </div> </div> </div> </div> </div></div>div is by far the most popular element, which is absolutely fine, but it's often being used in favor of other elements that would fit better. This overuse is nothing new, but the rise of JavaScript (JS) frameworks has amplified it.It would be a bit too easy to only blame JS frameworks, there are several reasons we use divs so much:Poor knowledge of HTML elements Lack of understanding why Insufficient CSS skills Default styles JS frameworks We don't care enough about the page Some elements are hard to style Poor knowledge of HTML elementsPaul Foster built this fantastic HTML memory test. Try it, you'll be surprised how much you don't remember and know. (Heads up: His test lists 115 elements because it includes svg, math, and t
3年前
記事のアイキャッチ画像
Workshop: Deep Dive on Accessibility Testing
Manuel Matuzović - Blog
I’ve teamed up with my friends at Smashing Magazine 😻 to share with you everything I know about web accessibility testing! In this smashing workshop we’ll talk about automatic and manual testing, screen reader basics, Single Page Applications, Dev Tools, and more.Sounds interesting? Great! Here are some more details about the workshop:What you will learn in this workshopWhich testing tools are available and most commonly used.How to assess the accessibility of a component or page.The difference between automatic and manual testing.How to use automatic accessibility testing tools and how to interpret the results.How to use the keyboard to discover accessibility bugs.Screen reader basics and how to use them for accessibility testing, both on desktop and mobile devices.How to test the accessibility of Single Page Applications.Common pitfalls of Single Page Applications and how to avoid them.How to integrate accessibility testing in your day-to-day development workflow.Running tests on th...
3年前
記事のアイキャッチ画像
A year in review: 2021
Manuel Matuzović - Blog
2021 was wild! That’s why I’ve decided to write an “A year in review” post for the first time.PersonalLet me start with the most important thing that happened in 2021: Our daughter Johanna was born on May 19th. I can’t describe how beautiful the entire experience was and still is. For the first two days, I wasn’t able to look at her for longer than 5 seconds without tearing up. Everything was just so emotional, beautiful, and overwhelming.Don’t get me wrong, life with a baby is exhausting, especially compared to how our life was before, but the positive things outweigh the lack of sleep and the new fears you have as a parent. Watching her grow and learn new stuff every day is amazing.Fun fact: I hid some Easter eggs on HTMHell regarding my daughter. The example I’m using in Issue #1 - iframe accessibility is “Visions of Johanna” by Bob Dylan and I’ve listed her as an executive producer in the credits of my first YouTube video. Another personal highlight of 2021 was our first vacation a
2年前
記事のアイキャッチ画像
Here’s what I didn’t know about :where()
Manuel Matuzović - Blog
This is part 4 of my series Here’s what I didn’t know about… in which I try to learn new things about CSS. This time I'm trying to find out what I didn’t know about the :where() pseudo-class.Okay, I’ll be honest. When I heard about the :where() pseudo-class for the first time, I wasn’t impressed because reading a rule like the following hurt my brain. :where(header, main, footer) p:hover { color: red;}It feels like using a shorthand property instead of longhand properties; fewer lines of code, but harder to process. I didn’t get the point, but a few days ago it clicked. Here’s what I didn’t know about :where():You can use it to lower the specificity of a selectorI believe it was on Andys blog where I saw this smart rule:ul[class] { margin: 0; padding: 0; list-style: none;}If a <ul> has no class, it’s probably a list in the true sense, so leave it untouched and display bullets. If the list has a class, it’s semantically still a list (in most browsers), but it’s likely that it doesn’t lo
2年前
記事のアイキャッチ画像
CSS Specificity Demo
Manuel Matuzović - Blog
I built an interactive demo to illustrate how specificity in CSS works.main { background: rgb(250 250 250 /0.6) !important;}Press the “Add selector” and “Remove selector” buttons to add or remove a selector in the list of declarations and see how the background color changes accordingly. Each selector will be added to the top of the list to prove that it has a higher specificity than the previous selector. Remove selector Add selectordocument.body.classList.add('body')document.body.setAttribute('id', 'body')document.documentElement.classList.add('step0') let step = 0; const messages = [ 'Selector: :where(body), background-color: gray', 'Selector: body, background-color: red', 'Selector: .body, background-color: blue', 'Selector: body.body, background-color: green', 'Selector: .body.body, background-color: orange', 'Selector: #body, background-color: brown', 'Selector: body#body, background-color: fuchsia', 'Selector: .body#body, background-color: salmon', 'Selector: #body#body, backgro
2年前
記事のアイキャッチ画像
Cascade Layers: First Contact
Manuel Matuzović - Blog
Earlier this week I learned about CSS Cascade Layers and now I’m all hyped up because I really like the concept. I’m eager to find out how we can use them to improve and rethink the architecture of our styles.I will not explain how CSS Cascade Layers work because Bramus and Stephanie have already done that and they did it much better than I ever could. I just want to get my feet wet and share my first impressions. If you’re new to the topic, read their articles first.Getting Started With CSS Cascade Layers by Stephanie EcklesThe Future of CSS: Cascade Layers (CSS @layer) by Bramus van DammeWhile I’m writing this blog post, I’m looking at a large site I’ve been working on and I’m trying to find scenarios in which cascade layers could’ve been useful.Overly specific base stylesIf you have a layer for base styles and another for your components, you don’t have to worry about selectors with high specificity in the base layer anymore.@layer base, components;@layer base { ul[class] { margin:
2年前
記事のアイキャッチ画像
Web Security Basics: XSS
Manuel Matuzović - Blog
I decided to learn more about areas of web development I don’t know a lot about. You know,…stuff like SEO and web security. I’ll share my findings here on my blog and I’ll try to do as much research as possible, but please keep in mind that I’m a noob concerning these topics.I began watching Feross Aboukhadijeh’s fantastic Web Security lecture, which inspired me to learn more about web security. This first post is about Cross Site Scripting (XSS). XSSXSS describes the practice of injecting malicious code into an otherwise trusted website, or, in other words, injecting JavaScript into an HTML document. The point of XSS is that the attacker can execute JavaScript on a page by supplying untrusted data and do stuff they otherwise wouldn’t be able to do. For example, reading users’ cookies and sending HTTP requests with these cookies.There are two types of XSS attacks: server and client XSS.Server XSSServer XSS occurs when the vulnerability is in the server-side code and the browser renders
2年前
記事のアイキャッチ画像
Bonn Meetup 7: Introduction to web accessibility and deceitful Lighthouse scores
Manuel Matuzović - Blog
This week I’ll be speaking at the Bonn Code Meetup about accessibility testing. I’m joining Konstantin Tieber who’ll talk about the What, Why, Who and How of building accessible web applications. I’ll show you how I built “The Most Inaccessible Site Possible With A Perfect Lighthouse Score”.Join us Online at 7pm CEST on Wednesday, February 23rdSchedule19:00 - 19:15 Arrival, get to know each otherMy blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Please, stop disabling zoom
Manuel Matuzović - Blog
I know that you’re not supposed to tell people what to do, but in this particular case I’m really tempted because recently I’ve noticed that a lot of websites are preventing users on mobile to zoom.I don’t know whether this is a trend, or just a coincidence, but I see a lot of these meta tags on sites:<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> This prevents users from being able to zoom a page on some browsers and operating systems. This can have serious negative consequences for people with low vision, elderly people and pretty much anyone who has to or wants to zoom in. If you want to see how problematic this is, visit espn.com, duesseldorf.de, thesun.co.uk, discord.com, or dhl.de, just to name a few.According to the HTTP Archive Web Alamac, 24% of deskt
2年前
記事のアイキャッチ画像
Divs are bad!
Manuel Matuzović - Blog
Yes, clickbait, I’m so sorry! Of course, divs are not bad. For example, they can be really useful,……when you need additional elements for styling.…for structuring content, when there’s no other suitable element.…when you need custom landmarks.Even though there’s nothing wrong with the div per se, some people, including me, still like to complain when they’re not used consciously.The issue with divs is not the quantity, although a large DOM can affect performance negatively, and an unnecessarily large document is harder to read and debug. The real problem is the placement. If you put a div in the wrong place, it can have serious negative side effects. Here are some examples:details and summaryIf you wrap the contents of a details element in a div, the browser or a screen reader might not recognize the summary element properly and display and announce a fallback text instead.Wrong<details> <div> <summary>Show info</summary> Hi, I'm the info! </div></details>Show info Hi, I'm the info! Ri
2年前
記事のアイキャッチ画像
Analyzing pages in a particular state with Lighthouse
Manuel Matuzović - Blog
Historically, Lighthouse has analyzed the cold pageload of a page only. Clicking the “Generate report” button reloads the page before Lighthouse runs its tests. This can be problematic when you want to run tests on parts of the UI that are only visible when the user interacts with it. For example, a fly-out navigation, a modal window, or the content in a disclosure widget.That has changed with Lighthouse v10. A new experimental feature in Chrome DevTools allows us now to analyze the page in a particular state. Here’s an example:When you click the “Show” button in this simple disclosure widget, an image appears. The image has no alt attribute and Lighthouse should report an error, but it reloads the page, and the image is gone when it runs the tests, because the state of the page doesn't persist.Starting with Lighthouse v10, you can also run tests on snapshots of a page. First, you have to enable this feature because it’s still an experiment: Open Chrome DevTools, press F1, click “Exper
2年前
記事のアイキャッチ画像
outline is your friend
Manuel Matuzović - Blog
If you open a plain HTML document with no CSS and you focus an interactive element like a button, link, or textarea, you’ll see that by default browsers use the outline property to highlight these elements.A blue outline around a focused button in Firefoxoutline is greatThe outline property is the perfect candidate for this job for several reasons.outline doesn’t break layout.Unlike the border property (if box-sizing is not set to border-box), outline doesn’t add to the width and height of an element. It just creates an outline without taking up any space.You can add spacing between the content and the outline using outline-offset. Outlines on Stephanie Eckles website have some extra spacing. You can customize the width, style, and color.Big, red, dotted outline around a link in a teaser on smashingmagazine.com:focus { outline-width: 3px; outline-style: dotted; outline-color: #d33a2c; outline-offset: 2px;}outline works great in forced color modes like Windows High Contrast Mode (WHCM)T
2年前
記事のアイキャッチ画像
Parents counting children in CSS
Manuel Matuzović - Blog
The other day I was driving home when suddenly it hit me: We can use :has() to determine how many children a parent element has.You might be thinking that Heydon Pickering already solved that 7 years ago in Quantity Queries for CSS, but that's not what I'm talking about./* Quantity Queries for CSS by Heydon Pickering *//* Three or more items */li:nth-last-child(n+3),li:nth-last-child(n+3) ~ li { background: red;}What I mean is that now we can style the parent element and other children differently depending on the number of items present anywhere in the parent element.Note: :has() is only available in Safari 15.4+, Chrome 105+ or behind a flag in Firefox.The following code checks if there are at least 3 list items in the list and adds a border to the parent if that's the case.ul:has(li:nth-child(3)) { border: 1px solid red;}A B(↑ no border)A B C(↑ red border)A B C D(↑ red border)We can adapt the selector a bit and only apply the styling if there are exactly three list items. ul:has(li:
2年前
記事のアイキャッチ画像
Buttons and the Baader–Meinhof phenomenon
Manuel Matuzović - Blog
Shortly after we got our new car, a Volkswagen T5, I noticed many people seemed to have the same car. Actually, it was everywhere.It felt like everyone had the same car. While sales of camping vans and cars that can be used for camping in fact have increased during the pandemic, there’s another reason I saw so many of them, the Frequency illusion or Baader–Meinhof phenomenon.The Frequency illusion, also known as the Baader–Meinhof phenomenon or frequency bias, is a cognitive bias in which, after noticing something for the first time, there is a tendency to notice it more often, leading someone to believe that it has an increased frequency of occurrence.Shortly after I started HTMHell a similar thing happened. Every other website seemed to have inaccessible buttons. While this can be explained by the Baader–Meinhof phenomenon, there’s actually data that confirms my feeling. According to the WebAim 1 Million report, 50.1% of 1 million tested websites contained empty links and 27.2% empty
2年前
記事のアイキャッチ画像
Day 1: custom properties and fallbacks
Manuel Matuzović - Blog
You can pass a second value to the var() CSS function which acts as a fallback for when the property has not been set.Fallbacksdiv { background-color: var(--not-set, #000);}/* Result: #000 background */The fallback can also be a custom property (with its own fallback).div { background-color: var(--not-set, var(--also-not-set, #00F));}/* Result: #00F background */When Fallbacks failIf you're not working with custom properties and you set a valid value for a property followed by another declaration with an invalid value, the second declaration will be ignored.div { background-color: #F00; background-color: blahaha;}/* Result: #F00 background */When the value in the second declaration is a custom property that doesn't exist, the declaration is not ignored. Either the property’s inherited value or its initial value, depending on whether the property is inherited or not, will be used instead.div { background-color: #F00; background-color: var(--not-set);}/* Result: transparent background */
2年前
記事のアイキャッチ画像
100 Days Of More Or Less Modern CSS
Manuel Matuzović - Blog
It’s time to get me up to speed with modern CSS. There’s so much new in CSS that I know too little about. To change that I’ve started #100DaysOfMoreOrLessModernCSS. Why more or less modern CSS? Because some topics will be about cutting-edge features, while other stuff has been around for quite a while already, but I just have little to no experience with it.My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 2: logical properties
Manuel Matuzović - Blog
Logical properties are a new way of working with directions and dimensions, one that allows you to control layout through logical, rather than physical mappings. This is especially useful, if you’re dealing with websites that are presented in different languages and writing modes, like right-to-left.Physical propertiesWe're used to working with physical properties like margin-right, top, or border-left. In the following example, list items are positioned horizontally, and each item has a right margin.HTML:<ul> <li>One</li> <li>Two</li> <li>Three</li></ul>CSS:li { background-color: #6befef; margin-right: 2rem;}OneTwoThreeVisualise marginThe first item “One” is at the left edge of its parent element.When you change the reading direction from right to left, you'd expect the first item to be positioned at the right edge of its parent, but it's not because physical properties don't change with the reading direction.HTML:<ul dir="rtl"> <li>One</li> <li>Two</li> <li>Three</li></ul>OneTwoThree
2年前
記事のアイキャッチ画像
Day 3: logical property shorthands
Manuel Matuzović - Blog
If you use a shorthand property like margin with all 4 values, the properties will always be applied in the direction top - right - bottom - left, no matter the reading direction.<button>Physical margin</button><button dir="rtl">Physical margin rtl</button>button { margin: 20px 40px 10px 100px;}/*LTR: 20px 40px 10px 100pxRTL: 20px 40px 10px 100px*/Physical marginPhysical margin rtlThis might be desired, but it could also happen that you want margin to respect the reading direction. Logical Properties introduce 2 new shorthand properties, margin-inline and margin-block. These properties take 1 or 2 values..logical { margin-inline: 5rem; /* start and end value (= left and right) */ margin-block: 5rem; /* start and end value (= top and bottom) */ margin-inline: 1rem 2rem; /* start / end value (= left / right in ltr) */ margin-block: 3rem 4rem; /* start / end value (= top / bottom in ltr) */}Unlike margin, margin-inline and margin-block respect the reading direction.<button>Logical margin<
2年前
記事のアイキャッチ画像
Day 4: the min() function
Manuel Matuzović - Blog
The min() function takes a comma separated list of expressions. The smallest value in the list will be selected.div { width: min(400px, 200px, 300px); /* width = 200px */}This example doesn’t make much sense because the value will always be 200px.min() shows its true power when you use relative units.div { width: min(100%, 800px);}If the available space is below 800px, it matches 100%. If it's more than 800px, it matches 800px. This is basically a shorter version of this.div { width: 100%; max-width: 800px;}My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 5: the max() function
Manuel Matuzović - Blog
The max() function takes a comma separated list of expressions. The largest value in the list will be selected.div { width: max(400px, 200px, 300px); /* width = 400px */}This example doesn’t make much sense because the value will always be 400px.max() shows its true power when you use relative units.div { width: max(300px, 50vw);}If 50vw is lower than 300px, width matches 300px. If 50vw is larger than 300px, it matches 50vw. This is basically a shorter version of this.div { min-width: 300px; width: 50vw;}PS: The next post is coming on Monday because weekends are for family and friends. ❤️My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 6: the :has() pseudo-class
Manuel Matuzović - Blog
:has() allows you to check whether a parent element contains specific children.In the following example, each .form-item that contains/has a child with the aria-invalid attribute set to “true” displays text in red color. (currently only in Chrome/Edge 105+ and Safari 15.4+)NameE-Mail<form> <div class="form-item"> <label for="name">Name</label><br> <input type="text" id="name" required aria-invalid="true"> </div> <div class="form-item"> <label for="email">E-Mail</label><br> <input type="text" id="email"> </div></form>.form-item { --color: #000; /* The default color is #000 */ color: var(--color);}input { /* The default border-color is #000 */ border: 1px solid var(--color);}/* If the .form-item contains an element with [aria-invalid="true"], the text and border color changes to #F00 */.form-item:has([aria-invalid="true"]) { --color: #F00;}My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 7: subgrids
Manuel Matuzović - Blog
Subgrid allows a grid-item with its own grid to align with its parent grid (currently only in Firefox 71+ and Safari 16+).In the following example, the div elements use the grid defined in the dl element. The result is that all the dt and dd elements are aligned in the same “columns” respectively, even though they’re not on the same level in the DOM.<dl> <div> <dt>HTML</dt> <dd>The HyperText Markup Language or HTML is the standard markup language for documents designed to be displayed in a web browser.</dd> </div> <div> <dt>JavaScript</dt> <dd>JavaScript often abbreviated JS, is a programming language that is one of the core technologies of the World Wide Web, alongside HTML and CSS</dd> </div></dl>dl { display: grid; gap: 0.5rem 2rem; grid-template-columns: auto 1fr;}div { display: inherit; grid-column: 1 / -1; grid-template-columns: subgrid;}HTML The HyperText Markup Language or HTML is the standard markup language for documents designed to be displayed in a web browser. JavaScript J
2年前
記事のアイキャッチ画像
Day 8: nesting :has()
Manuel Matuzović - Blog
The :has() pseudo-class cannot be nested; :has() is not valid within :has().<div> <p> <strong>I have a red and blue border in supporting browsers.</strong> </p></div>/* valid */div:has(p) { border: 4px solid red;}/* valid */p:has(strong) { border: 4px solid blue;}/* invalid */div:has(p:has(strong)) { border: 4px solid green;}I have a red and blue border in supporting browsers. Using a combined selector instead of nesting :has() is valid./* valid */div:has(p strong) { border: 4px solid green;}I have a green border in supporting browsers. My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 9: the inset shorthand property
Manuel Matuzović - Blog
The inset property is a shorthand for the top, right, bottom, and/or left properties. It implements the same multi-value syntax like margin.<div class="parent"> <div class="child"> At bottom right with 20px offset </div></div>.parent { width: 12rem; height: 12rem; position: relative;}.child { position: absolute; /* top: auto; right: 20px; bottom: 20px; left: auto */ inset: auto 20px 20px auto; width: 50%; height: 50%;}Just like margin, inset does not respect the reading direction. To work around that, use the inset-inline and inset-block shorthands..child { position: absolute; /* top: auto; bottom: 20px; in ltr */ inset-block: auto 20px; /* left: auto; right: 20px; in ltr */ inset-inline: auto 20px;}<div class="parent" dir="rtl"> <div class="child"> At bottom right with 20px offset </div></div>Are these shorthands useful? I don't know. I'll cover some use cases later in the series, but I wasn't able to come up with many scenarios where inset makes things much easier.My blog doesn't sup
2年前
記事のアイキャッチ画像
Day 10: global styles and web components
Manuel Matuzović - Blog
I was wondering what happens with HTML elements in web components when I add styles to the document. Under which circumstances do global styles defined in a style element or external stylesheet apply to these elements?As it turns out, it depends on how you create and use the components. In my test setup I have an HTML document, a stylesheet and three different components.styles.cssdiv { border: 2px solid red;}index.html<head> … <link rel="stylesheet" href="styles.css"></head><body> <basic-component></basic-component> <shadow-component></shadow-component> <slot-component> <div>Bye World!</div> </slot-component> <script src="basic-component.js" type="module"></script> <script src="shadow-component.js" type="module"></script> <script src="slot-component.js" type="module"></script></body>Web component without shadow DOMIf you add an element to a web component using JavaScript and you don’t attach it to the shadow DOM, styles defined outside the web component apply.basic-component.jsclass B
2年前
記事のアイキャッチ画像
Day 11: space-separated functional color notations
Manuel Matuzović - Blog
Functional color notations that existed before CSS Color Module Level 4 (rgb(), rgba(), hsl(), hsla()) used to only except comma-separated lists of arguments. That changes with Module Level 4, now you can also provide space-separated arguments. .div { width: 100px; height: 100px; } .div1 { background-color: rgb(255 0 0);} .div2 { background-color: rgb(0% 100% 0%);} .div3 { background-color: rgb(0 0 255 / 0.5);} .div4 { background-color: rgb(255 0 0 / 50%);}rgb valuesdiv { background-color: rgb(255 0 0);}Percentagesdiv { background-color: rgb(0% 100% 0%);}rgb values + alphadiv { background-color: rgb(0 0 255 / 0.5);}rgb values + percentage alphadiv { background-color: rgb(255 0 0 / 50%);}Summarybody { /* Comma-separated arguments */ background-color: rgb(255, 0, 0); background-color: rgb(0%, 100%, 0%); background-color: rgba(255, 0, 0, 0.5); background-color: rgba(0%, 0%, 100%); /* Space-separated arguments */ background-color: rgb(255 0 0); background-color: rgb(0% 100% 0%); background
2年前
記事のアイキャッチ画像
Day 12: max() trickery
Manuel Matuzović - Blog
I saw this interesting one-liner in a demo by Temani Afif..wrapper { margin-inline: max(0px, ((100% - 64rem) / 2)); }It’s basically a shorter way of writing this:.wrapper { max-width: 64rem; margin: 0 auto; width: 100%;}It’s not up to me to decide whether it’s smart to use this in production or not, but I want to break it down to fully understand what’s going on.Let’s work our way from the inside out.(100% - 64rem)This takes the available width and subtracts the maximum width of the wrapper. What’s left is the remaining space.((100% - 64rem) / 2)We take the remaining space and divide it by 2. We have to divide it because we want to use it for the left and right margin of the wrapper.max(0px, ((100% - 64rem) / 2));If 100% is less than 64rem, we would get a negative number, which would break the layout. The max() function ensures that the margin is always at least zero. It takes a comma separated list of expressions. The largest value in the list will be selected. If the value of our cal
2年前
記事のアイキャッチ画像
Day 13: the :where() and :is() pseudo-classes
Manuel Matuzović - Blog
The :where() and :is() pseudo-classes allow you to write large lists of selectors in a more compact form. You can combine selectors instead of writing repetitive lists.Combining input types/* Before */input[type="text"],input[type="email"],input[type="url"],input[type="tel"],input[type="password"],input[type="search"] { border: 2px solid;}/* After */input:where( [type="text"], [type="email"], [type="url"], [type="tel"], [type="password"], [type="search"]) { border: 2px solid;}Combining pseudo-classesa:is(:link, :visited) { color: green;}a:is(:hover, :focus) { text-decoration: none;}Now you might be thinking, “Uhm,…can’t I just use :where() instead of :is() and vice versa? What’s the difference?”.A fantastic question that I’ll answer in tomorrows post! :)My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 14: the difference between :is() and :where()
Manuel Matuzović - Blog
There's an important difference between :is() and :where().Let's take the following example. We have two buttons and we use :where() on the first button to apply a background color and :is() on the second button.<button class="button1">where</button><button class="button2">is</button>button:where(.button1) { background-color: rebeccapurple;}button:is(.button2) { background-color: rebeccapurple;}whereisVisually the buttons are identical, but the difference is the specificity of the selector. The button with the :where() pseudo-class has the same specificity as a simple tag selector (for example button {}) because the specificity of :where() is 0. The arguments in :where() don't add to the specificity of the selector. The button with the :is() pseudo-class has the same specificty as a combined selector (for example button.button2 {}) because :is() takes on the specificity of the most specific selector in its arguments./* Specificity: 0 0 1 (0 ids, 0 classes, 1 tag) */button:where(.button
2年前
記事のアイキャッチ画像
Day 15: the :modal pseudo-class
Manuel Matuzović - Blog
There are two methods you can use to open a <dialog> element, show() and showModal(). show() opens a dialog on top of the rest of the content, but you can still interact with content beneath. showModal() opens a modal dialog with a backdrop on top of the rest of the content, and you can’t interact with the rest of the page.You can use the :modal pseudo-class to style modal dialogs (dialogs opened via showModal()) differently.CloseShowShow modaldialog { border: 10px solid aqua;}:modal { border-style: dotted; border-color: fuchsia; padding: 4rem;}<dialog> yo! <button class="closeButton">Close</button></dialog><button class="showButton">Show</button><button class="showModalButton">Show modal</button>const showButton = document.querySelector('.showButton')const showModalButton = document.querySelector('.showModalButton')const closeButton = document.querySelector('.closeButton')const dialog = document.querySelector('dialog')showButton.addEventListener('click', e => { dialog.show()})showModa
2年前
記事のアイキャッチ画像
Day 16: the specificity of :has()
Manuel Matuzović - Blog
Just like with :is() and :not(), the specificity of :has() is replaced by the specificity of the most specific selector in its selector list argument. Unlike :nth-child() or :link, :has() itself doesn't add to the specificity.<div class="parent"> <p class="child">yo!</p></div>/* A tag and a class */div:has(.child) { background: red;}/* A tag: specificty too low */div { background: blue;}/* A class: specificty too low */.parent { background: green;}/* A tag and a class: same specificty as div:has(.child) */div.parent { background: orange;}yo!My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 17: the :picture-in-picture pseudo-class
Manuel Matuzović - Blog
You can use the :picture-in-picture pseudo-class to style an element, usually a <video>, which is currently in picture-in-picture mode (PIP).Clicking the following button puts the video in picture-in-picture mode in supporting browsers (Chrome, Edge, Safari, Opera). Firefox doesn't support the API, but you can right-click the video and select “Watch in Picture-in-Picture“.Toggle PIPWhen the video is playing in PIP mode, the placeholder for the video switches to the :picture-in-picture state. Contrary to the information in the support table on MDN, none of the browsers, except for Safari, supports the pseudo-class. At least, according to my tests.:picture-in-picture { opacity: 0.3; filter: blur(5px);} { togglePictureInPicture() }) function togglePictureInPicture() { if (document.pictureInPictureElement) { document.exitPictureInPicture(); } else if (document.pictureInPictureEnabled) { video.requestPictureInPicture(); } }Here's how the video placeholder, which by default is not blurred an
2年前
記事のアイキャッチ画像
Day 18: inheritable styles and web components
Manuel Matuzović - Blog
We already know that we can encapsulate styles within a web component by adding elements along with the styles to the shadow DOM. Global style declarations from outside don’t overwrite styles inside the web component.If you look at the following component, you’ll notice that it uses the same font as the rest of the page, even though I haven't applied any styles to the web component. If styles were completely encapsulated, I would expect the component to use a default font like Times, but the web component inherits styles from its parent elements. HTML:<shadow-component></shadow-component>JS:class ShadowComponent extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); this.shadowRoot.innerHTML = `<div>Hello World!</div>` }}customElements.define('shadow-component', ShadowComponent);Hello World!` }}customElements.define('shadow-component', ShadowComponent);If I wrap the component in a <div> and a set a color on the div, the color of the text inside the web compon
2年前
記事のアイキャッチ画像
Day 19: the placeholder-shown pseudo-class
Manuel Matuzović - Blog
You can use the :placeholder-shown pseudo-class to select input fields with a placeholder that haven't been filled out yet.input:placeholder-shown { outline: 5px solid blue;}<p> <label for="name">Name</label> <input type="text" id="name" placeholder="your name…" value="Johanna"></p><p> <label for="email">E-Mail</label> <input type="email" id="email" placeholder="[email protected]"></p>Name E-Mail PS: Yeah, I know, that one has been around for quite a while already, but I started writing CSS 15 years ago. So anything that was published after 2015 is modern CSS for me. :)My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 20: the scrollbar-gutter property
Manuel Matuzović - Blog
The scrollbar-gutter property allows you decide whether content within an element fills the total available space or if it stops at the scrollbar gutter. The scrollbar gutter is the space between the inner border edge and the outer padding edge of an element used by the scrollbar.By default, if the content in an element is not overflowing, there's no gutter.Overflowing contentscrollbar-gutter: autoYou can set scrollbar-gutter to stable to always show the gutter. This allows you to create more consistent and stable layouts..gutter { scrollbar-gutter: stable;}Overflowing contentscrollbar-gutter: stableMy blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 21: conic gradients
Manuel Matuzović - Blog
You can create gradients with color transitions rotated around a center point, rather than radiating from the center, by using the conic-gradient() function.There are many options to customize conic gradients.Colors onlyThe simplest way to create a conic gradient is to pass a list of colors to the function.div { background-image: conic-gradient(aqua, fuchsia, salmon, aqua); }AngleBy default, the gradient starts at 0 degrees and rotates clockwise.div { background-image: conic-gradient(aqua, fuchsia); }You can pass an angle, preceded by the “from” keyword, to change the starting point.div { background-image: conic-gradient(from 90deg, aqua, fuchsia); }Off-centered gradientBy default, the center pointer of the gradient is at the center of the element. You can change that by passing a length, percentage, or keyword.Lengthdiv { background-image: conic-gradient(from 90deg at 4rem 4rem, aqua, fuchsia);}Percentagediv { background-image: conic-gradient(from 90deg at 25% 75%, aqua, fuchsia);}Key
2年前
記事のアイキャッチ画像
I broke the rules.
Manuel Matuzović - Blog
When I opened Twitter on Monday morning, I saw this:After careful review, they determined that my account broke the Twitter Rules. Okay, let's have a look at the rules to get an idea of what could've caused this ban. You break the rules if your tweets contain content related to anything in this list:ViolenceTerrorism/violent extremismChild sexual exploitationAbuse/harassmentHateful conductPerpetrators of violent attacksSuicide or self-harmSensitive media, including graphic violence and adult contentIllegal or certain regulated goods or servicesI can assure you I tweeted nothing related to any of these things. Also, I didn't spam, I didn't try to manipulate elections, I didn't impersonate anyone, I didn't share synthetic or manipulated media, and I did not violate others’ intellectual property rights.So, what happened? I have absolutely no idea! Here's a rough outline of the events:21.10. Comment on Unas questionOn Friday Una asked on Twitter What do you want to see on the web platform
2年前
記事のアイキャッチ画像
Day 22: the ::backdrop pseudo-element
Manuel Matuzović - Blog
You can use the ::backdrop pseudo-element to style the backdrop of modal dialogs and elements which have been placed in fullscreen mode using the Fullscreen API. ::backdrop { background-color: rgb(0 0 155 / 0.5);}.dialog2::backdrop { background: conic-gradient(red, orange, yellow, green, red); outline: 20px solid white; outline-offset: -40px;}dialog { width: min(30rem, 100%); aspect-ratio: 16 / 9;}::backdrop { background-color: rgb(0 0 0 / 0.5);}closeshow modalYou don't have to limit yourself to semi-transparent background color.::backdrop { background: conic-gradient(red, orange, yellow, green, red); outline: 20px solid white; outline-offset: -20px;}closeshow modal { dialog1.showModal()})showModal2.addEventListener('click', e => { dialog2.showModal()})close1.addEventListener('click', e => { dialog1.close()})close2.addEventListener('click', e => { dialog2.close()})My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 23: the lab() color function
Manuel Matuzović - Blog
The lab() color function allows you to pick colors from the CIELAB color space, which is device-independant and covers the entire gamut (range) of human color perception.Currently, the CSS colors we can define are in the sRGB color space. For the longest time, professional monitors weren’t able to display all possible colors in this range. So, using sRGB colors was absolutely sufficient, but that’s not true anymore. Nowadays, monitors can display much more colors than exist in the sRGB color space. With lab() we get access to these colors (currently Safari 15+ only).The function takes 3 space-separated values.div { background-color: lab(78% -64 -160);} Screenshot of Michelle Barkers “LAB color explorer” on CodePenl - lightnessThe first value defines the lightness. It's typically a number between 0% (representing black) and 100% (representing white). It's typically a number between 0% and 100% because the value can exceed 100% up to 400% representing extra-bright whites on some systems.
2年前
記事のアイキャッチ画像
Day 24: the backdrop-filter property
Manuel Matuzović - Blog
The backdrop-filter property allows you to apply CSS filters to the area behind an element. This could be the background of an element or the backdrop of a dialog.In the following example, the parent element has a background image, nothing special about it, but the inner elements all have a backdrop-filter applied which changes how the image beneath them is displayed.<div class="parent"> <div class="blur">Blur</div> <div class="invert">Invert</div> <div class="hue">Hue</div> <div class="grayscale">Grayscale</div></div>.parent { background-image: url("/images/neue-donau.webp");}.blur { backdrop-filter: blur(5px);}.invert { backdrop-filter: invert(1);}.hue { backdrop-filter: hue-rotate(260deg);}.grayscale { backdrop-filter: grayscale(100%);} * { opacity: 0;}.inner { padding: 1rem; font-size: 2rem; text-shadow: 1px 1px 3px #fff; transition: opacity 0.3s;} BlurInvertHueGrayscaleNotice how the filters don’t affect the text? Yeah, that’s the difference between backdrop-filter and filter. The
2年前
記事のアイキャッチ画像
Day 25: scrollbar gutters in body and html
Manuel Matuzović - Blog
When I wrote about the scrollbar-gutter property, my first thought was “omg! I'll put this in my reset stylesheet and use it on the <body> by default”. I wanted to do that in order to prevent the page from “jumping” when switching from a long to a short page, a page with overflow to one without.Here's a quick demo to illustrate the issue. When switching from a page with a scrollbar to a page without, you can see how the whole page shifts to the left because the scrollbar takes up space on longer pages.So I tried this…body { scrollbar-gutter: stable;}…and it didn't work.I looked at the spec and there it says:So, overflow on the body is propagated to the viewport, which absolutely makes sense. Just try to set a width on the body with a lot of content, you'll see how the width changes, but the scrollbar is still on the inline end of the viewport.If I understand correctly, scrollbar-gutter has no effect on the body because overflow is propagated to the viewport, but scrollbar-gutter isn't.
2年前
記事のアイキャッチ画像
Day 26: using combinators in :has()
Manuel Matuzović - Blog
You already know that the :has() pseudo-class allows you to check whether a parent element contains certain children, but you can also make this selector more specific, or check other relations the element might have.Child combinatorsYou can check whether an element contains a specific direct child element. For example, if you have a fieldset and you want to make sure that it contains a legend and that this legend is actually a direct child item of the fieldset, which is important, you could use the child combinator (>) in your :has() pseudo-class. legend)) { border: 10px solid red; }fieldset:not(:has(> legend)) { border: 10px solid red;}<fieldset> <div> <legend>Letters</legend> </div> <input type="radio" name="letters" id="a"> <label for="a">a</label> <input type="radio" name="letters" id="b"> <label for="b">b</label> </div></fieldset> Letters a b Next-sibling combinators:has() is not just a parent selector, you can select elements based on other relations, too. By using the next-sibl
2年前
記事のアイキャッチ画像
Your account is permanently suspended
Manuel Matuzović - Blog
On October 23rd I got shadowbanned on Twitter, followed by a permanent suspension on October 25th. As someone who was very active on Twitter, I was surprised, shocked, and sad that this happened. Especially because I didn’t know why it happened.Some of you might think, “Who cares, it’s just social media?!”, and yeah, you’re right, it is just social media, but it was a pretty big deal. For me personally, I’ll go into detail about why later in this post, and generally because I got suspended without a clue why and with no notice. That’s something that shouldn’t happen on one of the biggest social media sites worldwide.indie web. Some were concerned about their freedom of speech, and some believed that things will get better once Elon Musk takes over. Others talked about AI and how dangerous algorithms can be.Owning your ContentMany people pointed out that this suspension was a perfect example of how important it is to own your own content. Owning your content means that you don’t create
2年前
記事のアイキャッチ画像
Day 27: the font-variation-settings property
Manuel Matuzović - Blog
Adjustable features of a variable font are called axes. You can use the font-variations-settings property to change these features by specifying the four letter axis name along with a value. @font-face { font-family: 'Saira'; font-style: normal; font-weight: 400; font-stretch: 100%; font-display: swap; src: url(/blog/2022/100daysof-day27/Saira-VariableFont.woff2) format('woff2');}.demo { font-family: 'Saira'; font-size: 3rem;}.demo2 { font-variation-settings: 'wght' 736;}.demo3 { font-variation-settings: 'wdth' 36;}.demo4 { font-variation-settings: 'wght' 736, 'wdth' 36;}For example, the Saira variable font has two axes, weight ('wght') and width ('wdth'). This is how the font looks like by default:This is just a test.You can set the weight to a value between 100 and 900.p { font-variation-settings: 'wght' 736;}This is just a test.You can set the width to a value between 50 and 125.p { font-variation-settings: 'wdth' 36;}This is just a test.Of course, you can also combine them.p { font
2年前
記事のアイキャッチ画像
Day 28: custom properties and web components
Manuel Matuzović - Blog
We already know that we can encapsulate styles within a web component and we know that web components inherit styles. Another interesting feature of web components in terms of CSS is that custom properties used in a web component can be modified from the outside.Let's take this basic alert component. ` this.shadowRoot.append(styles) this.shadowRoot.append(content) }}customElements.define('matuzo-alert', Alert); Please confirm your e-mail address by clicking the link in the e-mail we just sent you.class Alert extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); const styles = document.createElement('style'); styles.textContent = ` div { background-color: rgb(136 177 255 / 0.5); color: rgb(0 0 0); font-weight: bold; padding: 1rem; } ` const content = document.createElement('div'); content.innerHTML = ` <slot></slot> ` this.shadowRoot.append(styles) this.shadowRoot.append(content) }}customElements.define('matuzo-alert', Alert);<matuzo-alert> Please confirm you
2年前
記事のアイキャッチ画像
Day 29: !important custom properties
Manuel Matuzović - Blog
Using !important with custom properties might not work as you expect.If you look at the following example, which color does the text have?.example1 { --color: red; color: var(--color) !important; color: blue;}Show .example1 I'm red!Makes sense! By using !important we make the first color declaration more important than the second one.Now, what about this? Which color does the text have now?.example2 { --color: red !important; color: var(--color); color: blue;}Show .example2 I'm blue!In order to understand that, we have to look at the spec. There it says:Custom properties can contain a trailing !important, but this is automatically removed from the property’s value by the CSS parser,…Aha! It's okay to use it, but it will be removed from the value by the parser, and since it's removed, the second color declaration overwrites the first one. Why can we use it, if the CSS parser removes it anyway? Well, because the sentence continues:…and makes the custom property "important" in the CSS cas
2年前
記事のアイキャッチ画像
Day 30: the hwb() color function
Manuel Matuzović - Blog
Like the lab() color function, hwb() is one of the more recent methods for defining colors in CSS. Just like rgb() and hsl() it uses colors from the sRGB color space. HWB, which stands for hue-whiteness-blackness, describes colors with a starting hue, then a degree of whiteness and blackness to mix into that base hue.The function takes 3 space-separated values.div { background-color: hwb(234deg 30% 34%);}h - hueThe first value defines the hue. It's an angle of the color circle given in degs, rads, grads, or turns. The value can also be a unitless number, which defaults to deg.The color circle starts and ends with red (red=0deg=360deg), green is at 120deg and blue at 240deg.div { background-color: hwb(0 0% 0%);} Screenshot of Stefan Judis' “hwb() playground”div { background-color: hwb(206 0% 0%);}w – whitenessThe second parameter specifies the amount of white to mix in, as a percentage from 0% (no whiteness) to 100% (full whiteness).div { background-color: hwb(206 68% 0%);}b - blackness
2年前
記事のアイキャッチ画像
Day 31: logical border properties
Manuel Matuzović - Blog
Just like for margin or padding, there are also logical property variations for border properties.Originally there were 4 shorthand properties we could use for defining borders.border - 1, 2, or 3 values (size, style, color)border-width - 1, 2, 3, or 4 size values for the different sidesborder-style - 1, 2, 3, or 4 style values for the different sidesborder-color - 1, 2, 3, or 4 color values for the different sidesAnd we could do the same for each physical side (top, right, bottom, left).border-left - 1, 2, or 3 valuesborder-left-width - A size valueborder-left-style - A style valueborder-left-color - A color valueNow there are a couple of more properties:border-blockborder-block - 1, 2, or 3 values (size, style, color)border-block-width - 1 or 2 size values (a single value for both sides or one for each)border-block-style - 1 or 2 style valuesborder-block-color - 1 or 2 color valuesdiv { border-block: solid;}div { border-block: 20px solid aqua;}div { border-block-color: green; border-
2年前
記事のアイキャッチ画像
Workshop: Deep Dive on Accessibility Testing
Manuel Matuzović - Blog
I’ve teamed up with my friends at Smashing Magazine 😻 to share with you everything I know about web accessibility testing! In this smashing workshop we’ll talk about automatic and manual testing, screen reader basics, Single Page Applications, Dev Tools, and more.Sounds interesting? Great! Here are some more details about the workshop:What you will learn in this workshopWhich testing tools are available and most commonly used.How to assess the accessibility of a component or page.The difference between automatic and manual testing.How to use automatic accessibility testing tools and how to interpret the results.How to use the keyboard to discover accessibility bugs.Screen reader basics and how to use them for accessibility testing, both on desktop and mobile devices.How to test the accessibility of Single Page Applications.Common pitfalls of Single Page Applications and how to avoid them.How to integrate accessibility testing in your day-to-day development workflow.Running tests on th...
2年前
記事のアイキャッチ画像
Day 32: the clamp() function
Manuel Matuzović - Blog
The clamp() function defines a minimum value, a preferred value, and a maximum value..div { border: 1em solid hwb(200 0% 0%); padding: 1rem;}.minmax { width: max(300px, min(90%, 700px));}.clamp { width: clamp(300px, 90%, 700px);}.max { width: max(300px, 90%);}.min { width: min(90%, 700px);}A quick recap of min() and max() before we talk about clamp():We can use the min() function to define a maximum value for a property. It's the maximum value we define because in the list of provided parameters, min() will always pick the smallest value. For example, width: min(700px, 90%) is always 700px or less, which means that the maximum width is 700px.div { width: min(90%, 700px);}700px or less with no min-widthWe can use the max() function to define a minimum value for a property. It's the minimum value we define because in the list of provided parameters, max() will always pick the largest value. For example, width: max(300px, 90%) is always 300px or more, which means that the minimum width is
2年前
記事のアイキャッチ画像
Day 33: Mathematical expressions in min(), max(), clamp()
Manuel Matuzović - Blog
You can use full math expressions in the comparison functions min(), max(), and clamp(). There’s no need to nest a calc() function inside.Writing…div { border: max(20px, calc(1vw + 10px)) solid;}…is the same as writing…div { border: max(20px, 1vw + 10px) solid;}You can also use custom properties..var { --extra: 10px; border-width: max(20px, 1vw + var(--extra));}Complex expressions are also possible.div { width: clamp(50px * 4 * 1.5, (100% / 2) * 2, 400px * 2);}My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 34: :is() or :where()
Manuel Matuzović - Blog
Thoughts on when it’s better to use :is() over :where() and vice versa.The other day, I posted this code snippet on social media, asking people whether it was readable.summary:where(:hover, :focus-visible)::after { transform: rotate(180deg);}Some people responded they prefer :is() over :where() because it’s shorter or less typing. Others said they liked :where() better because grammatically it made more sense to them or because it just sounded better. These sound like valid reasons to pick one over the other, but they shouldn’t be (the main) reasons. As we already know, there is an important difference between :is() and :where(). The specificity of :where() is always 0, while :is() takes on the specificity of the most specific selector in its arguments.I thought that was clear to me, but a brief discussion following my initial question made me realize that I needed to put a bit more thinking into the topic. Kilian asked me whether I find myself defaulting to :is() or :where(), and I re
2年前
記事のアイキャッチ画像
Day 35: forgiving selectors
Manuel Matuzović - Blog
There's a difference between listing selectors in :where(), :is(), and :has() and listing them in a regular selector list.Let's say you have a button with the class .button and you apply the following styles..button:hover { background-color: hwb(100 0% 20%);}<button class="button">I'm a button</hover>I'm a buttonNothing special, the color just changes on hover. If you add more and different selectors to this rule, it still works..button:hover,.button:focus,#btn { background-color: hwb(100 0% 20%);}I'm a buttonHere's were it gets interesting: If one of the selectors in your list of selectors is invalid, the whole rule becomes invalid and declarations apply to none of the selectors..button:hover,.button:focus,$btn { background-color: hwb(200 20% 0%);}I'm a buttonEven using a pseudo-class that doesn't exist or that isn't supported by the browser invalidates the whole rule..button:hover,.button:focus,.button:touch { background-color: hwb(200 20% 0%);}I'm a buttonSo, a downside to using a s
2年前
記事のアイキャッチ画像
Day 36: :has() and pseudo-elements
Manuel Matuzović - Blog
We already know that we can select an element based on the presence of a certain child element (in Chrome/Edge 105+ and Safari 15.4+), but there are limitations.<p> <strong>World</strong>!</p>p:has(strong) { background-color: aqua;}World!This works well with actual elements, but it doesn't work with pseudo-elements.p::before { content: "Hello";}p:has(::before) { background-color: salmon;}World!According to the spec, that's because Pseudo-elements are generally excluded from :has() because many of them exist conditionally, based on the styling of their ancestors, so allowing these to be queried by :has() would introduce cycles..For the sake of completeness, of course :has() works with pseudo-classes.p:has(:hover) { background-color: salmon;}World!My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 37: cascade layers
Manuel Matuzović - Blog
Cascade layers introduce a new way of managing specificity in CSS.Let’s say we’re using a combination of a tag and an attribute selector for styling e-mail input fields. This declaration is part of our base stylesheet and comes early in the stylesheet. Later in the document, we want to use a class to overwrite parts of the base styling:input[type="text"],input[type="email"] { border-color: hwb(0 0% 0%); border-style: solid; border-width: 3px;}.form-item { border-color: hwb(120 0% 40%);}E-mail This won’t work because input[type="email"] is more specific than .form-item.Using !importantWe could use !important, but we all know that this probably isn’t the best idea in the long term.input[type="text"],input[type="email"] { border-color:hwb(0 0% 0%); border-style: solid; border-width: 3px;}.form-item { border-color: hwb(120 0% 40%) !important;}Increasing selector specificityWe could increase the specificity of the second selector.input[type="text"],input[type="email"] { border-color:hwb(0 0
2年前
記事のアイキャッチ画像
Day 38: vh, svh, lvh, and dvh
Manuel Matuzović - Blog
Using the viewport unit vh in desktop browsers is usually straight-forward, 100vh matches the height of the viewport. On mobile that's different because the viewport height changes depending on whether or not certain user interface elements are visible, 100vh doesn't always match the height of the viewport.On mobile we have the small viewport and the large viewport. According to the spec, the small viewport is the viewport sized assuming any UA [User Agent/Browser] interfaces [for example the address bar] that are dynamically expanded and retracted to be expanded.The large viewport is the viewport sized assuming any UA interfaces that are dynamically expanded and retracted to be retracted.The problem with 100vh on mobile is that it doesn’t respect whether user interface elements are expanded or not. It usually always matches the large viewport. CSS introduces new viewport units to address that issue.You can use svh for the small viewport and lvh for the large viewport.div { height: 100
2年前
記事のアイキャッチ画像
Day 39: comma-separated functional color notations
Manuel Matuzović - Blog
On day 11 I've introduced you to space-separated functional color notations. Early color functions like rgb() and hsl() support both the old comma-separated and the new space-separated syntax./* ✅ works */div { background-color: rgb(255, 210, 210); color: hsl(150, 76%, 20%);}/* ✅ works */div { background-color: rgb(255 210 210); color: hsl(150 76% 20%);}On the other hand, new color functions like lab(), hwb(), lch(), or oklch() only support the space-separated syntax./* ✅ works */div { background-color: hwb(0deg 82% 0%); color: lab(33% -31 16);}/* ❌ doesn't work */div { background-color: hwb(0deg, 82%, 0%); color: lab(33%, -31, 16);}My blog doesn't support comments yet, but you can reply via [email protected].
2年前
記事のアイキャッチ画像
Day 40: unlayered styles
Manuel Matuzović - Blog
On day 37 we learned that we can get more control over specificity by creating layers. That first, simple example is pretty straightforward, but what happens if we mix layered and unlayered styles?Let's start nice and simple with a single layer. The border of this quote is red.<blockquote> There's only one Return, okay, and it ain't of the king...</blockquote>@layer base { blockquote { border: 4px solid red; padding: 1rem; }}If we add another layer, the border color turns green because a layer defined later in the document has precedence over a layer defined earlier.@layer base { blockquote { border: 4px solid red; padding: 1rem; }}@layer component { blockquote { border-color: green; }}If we add unlayered styles after the second layer, the color turns hotpink. Not because the declaration comes later in the document, but because unlayered styles have the highest priority and always* overwrite layered styles.*Okay, not always, but we'll talk about that in another post.@layer base { block
2年前
記事のアイキャッチ画像
Day 41: custom properties and url()s
Manuel Matuzović - Blog
Let’s say you want to swap the background image of an element based on a certain condition, like whether it’s pressed, using custom properties.button { --background-image: "/not-pressed.svg"; background: url(var(--background-image));}button[aria-pressed="true"] { --background-image: "/pressed.svg";}This looks fine, but it doesn't work because var(--background-image) contains invalid characters. The reason the argument is invalid is that url() works both with quotes url("image.svg") or url('image.svg') and without quotes url(image.svg). By passing a value without quotes you're not passing a string to a CSS function, but you're creating an url-token and this token expects a certain format that requires characters like ( to be escaped.“Why custom properties don't work with the url() CSS function” by the amazing Stefan Judis.To work around that issue, you have to move the url() function into the value of the custom property.button { --background-image: url("/not-pressed.svg"); background:
1年前
記事のアイキャッチ画像
Day 42: aspect-ratio
Manuel Matuzović - Blog
Yes, I know, aspect-ratio is not the hottest shit, but Safari only starting supporting it in version 15 and there’s a lot I didn’t know about the property. That’s reason enough for me to write about it. :)Defining ratiosYou can use the aspect-ratio property to define the preferred aspect ratio for a box by defining a preferred width and height.The maximum width of the following element is 400px, and due to the defined ratio of 16 / 9 the height equals 225px (400 / 16 * 9) = 225). If the available width gets below 400, the height scales accordingly.div { aspect-ratio: 16 / 9; /* aspect-ratio: width / height */ max-width: 400px;}Instead of writing aspect-ratio: 16 / 9 we can also write aspect-ratio: 400 / 225.div { aspect-ratio: 400 / 225; max-width: 400px;}SquaresIf you want to create a square, you need a ratio of 1:1, or 42:42, or 742617000027:742617000027;div { aspect-ratio: 1 / 1; max-width: 400px;}That's the same as writing aspect-ratio: 1 because if you omit the second value, the v
1年前
記事のアイキャッチ画像
Day 43: grouping layers
Manuel Matuzović - Blog
Cascade layers can be grouped by nesting layer rules.If you work on a large style sheet, you might want to create cascade layers to group different types of declarations. In order to give your layers even more structure and control, you can also group declarations within layers.Consider the following example. We have a layer for reset styles, base styles, components, and theming.@layer reset { body { margin: 0; }}@layer base { body { font-size: 1.6rem; }}@layer components { p { border: 1px solid; }}@layer theme { p { border-color: red; }}There's nothing wrong with that, but it might make sense to group similar layers. For example, you could group reset and base styles and component and theme styles.@layer base { @layer reset { body { margin: 0; } } @layer defaults { body { font-size: 1.6rem; } }}@layer components { @layer structure { p { border: 1px solid; } } @layer theme { p { border-color: red; } }}The same rules in terms or prioritization that apply to root layers also apply to nes
1年前
記事のアイキャッチ画像
Day 44: logical floating and clearing
Manuel Matuzović - Blog
Thanks to Flexbox and CSS Grid no one seems to talk about float and clear anymore,…except for me now because there's news.Floating and clearing has lost its importance for layout, but they are still useful properties. Just like for margin or border, you can now use logical properties for floating and clearing.img { float: inline-start; /* or inline-end */}p { clear: inline-start; /* or inline-end */}Gus Polinski, the "Polka King of the Midwest," was the clarinet player and lead musician of a polka band, the Kenosha Kickers.Gus first appears in the Scranton Airport when Kate is unable to fly to Chicago on Christmas Eve because all flights are fully booked. Upon hearing about her dilemma, Gus offers her a ride, which Kate gladly accepts.Source: Gus_PolinskiGus Polinski, the "Polka King of the Midwest," was the clarinet player and lead musician of a polka band, the Kenosha Kickers.Gus first appears in the Scranton Airport when Kate is unable to fly to Chicago on Christmas Eve because all
1年前
記事のアイキャッチ画像
Day 45: the specificity of ::slotted() content
Manuel Matuzović - Blog
When you pass an element to a web component through a <slot>, you can select that element using the ::slotted() pseudo-element and apply additional styles.Let's take the following component. There's a paragraph in the shadow DOM and another paragraph coming from the light DOM, passed through a <slot>, and there's a global style turning the background color of paragraphs aqua.p { background-color: aqua;}class SlotComponent extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); const content = document.createElement('div') content.innerHTML = ` <p>not slotted</p> <slot></slot> ` this.shadowRoot.appendChild(content) }}customElements.define('slot-component', SlotComponent);<slot-component> <p>slotted</p></slot-component>not slotted ` this.shadowRoot.appendChild(content) } }customElements.define('slot-component', SlotComponent);class SlotComponent2 extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); const styles = document.createEleme
1年前
記事のアイキャッチ画像
Day 46: ordering layers
Manuel Matuzović - Blog
By default, cascade layers are stacked in the order they are defined, but you don’t have to rely on it. You can determine the order in one place.In the following example, the border color of the paragraph is first red, then blue, then rebeccapurple, and finally green. @layer base { p { border: 10px solid red; }}@layer framework { p { border-color: blue; }}@layer components { p { border-color: rebeccapurple; }}@layer theme { p { border-color: green; }}You can change that order by defining layers first in a comma-separated list, starting with @layer.@layer base, components, theme, framework;@layer base { p { border: 10px solid red; }}@layer framework { p { border-color: blue; }}@layer components { p { border-color: rebeccapurple; }}@layer theme { p { border-color: green; }}The order of appearance of the @layer blocks doesn't matter any more, the order in the @layer list does. The border color of the paragraph is now first red, then rebeccapurple, then green, and finally blue.Oh, and of c
1年前
記事のアイキャッチ画像
Day 47: the overscroll-behavior property
Manuel Matuzović - Blog
You can use the overscroll-behavior property to disable scroll-chaining.If you scroll the inner box in the following example to the end and you keep scrolling, the outer box starts scrolling, too, and finally the whole page.In some cases this behavior is not desirable. You can use overscroll-behavior to prevent scrolls from chaining..inner { overscroll-behavior: none;}My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 48: inset 0
Manuel Matuzović - Blog
On day 9 I’ve talked about the inset shorthand properties inset, inset-inline, and inset-block. I don’t believe that I will need those often, but inset can come in handy when you want one element to fill another element entirely.If you have an outer element and an inner element and you want the inner element to fill its parent, you can use absolute positioning and set top, right, bottom, and left to 0.<div class="outer"> <div class="inner"> </div></div>.outer { border: 10px solid hotpink; position: relative; width: 7rem; height: 7rem;}.inner { background: aqua; position: absolute; top: 0; right: 0; bottom: 0; left: 0;}Instead, you could also just set inset to 0..inner { position: absolute; inset: 0; background: aqua;}Of course, this also applies to a fixed positioned element that you want to fill the viewport with..inner { position: fixed; inset: 0; background: aqua;}My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 49: layering entire style sheets
Manuel Matuzović - Blog
You can use @import to load entire style sheets into a cascade layer.@import url("path/to/the/styles.css") layer(layername);For example, you could load something like Bootstrap into a dedicated third-party layer.@layer third-party, base, components, utility;@import url("https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css") layer(third-party);@layer base { body { /* my custom styles */ }}<button type="button" class="btn btn-primary">Primary</button>PrimaryAn important thing to know when importing styles is that it matters where you put the @import rule. In the spec it says:Any @import rules must precede all other valid at-rules and style rules in a style sheet (ignoring @charset and empty @layer definitions) and must not have any other valid at-rules or style rules between it and previous @import rules, or else the @import rule is invalid.This is invalid:@layer third-party, base, components, utility;@layer base { body { /* my custom styles */ }}@import url("https://c
1年前
記事のアイキャッチ画像
Day 50: :has(:not()) vs. :not(:has())
Manuel Matuzović - Blog
Something I was tripping over when I began learning about :has() was the combination with :not().Let me show you what I got wrong by using an example. Let's say we have two cards, each with a heading and some text. One of them also contains an image. <div class="card"> <h2>Card with image</h2> <img src="https://assets.codepen.io/144736/skateboard.jpg" alt="" /> <p>text</p></div><div class="card"> <h2>Card without image</h2> <p>text</p></div>Card with imagetextCard without imagetextNow we want to add additional styling to cards without an image. If a card doesn't contain an image, we want to remove the margin on the heading and change the border-style..card:has(:not(img)) { border-style: dotted;}.card:has(:not(img)) h2 { margin-top: 0;}Card with imagetextCard without imagetextThe styles apply to both cards, no matter whether an image is present. That's because .card:has(:not(img)) means “select a .card that has any element that is not an image”. This means that the selector only wouldn'
1年前
記事のアイキャッチ画像
Day 51: aspect-ratio and replaced elements
Manuel Matuzović - Blog
Most elements have no preferred aspect ratio. On day 42 I’ve explained how you can use the aspect-ratio property to define a ratio for these elements. Replaced elements like <iframe>, <video>, <embed>, or <img>, on the other hand, have an intrinsic aspect ratio. This means that you don’t have to define one using the aspect-ratio property and they will scale naturally. You can change the aspect ratio of an image by using aspect-ratio and defining either a height or width with a value other than auto.img { width: 400px; aspect-ratio: 1;}The default value of the aspect-ratio property is auto (depending on the element, it’s either no preferred aspect ratio or the natural, intrinsic aspect ratio.). You can change the value to a ratio (1, 16/9, 666/666, etc.), or you can do both..autoAndRatio { width: 400px; aspect-ratio: auto 3 / 1;}If you both specify auto and a ratio together, replaced elements will use their natural aspect ratio (auto) and all other elements the specified ratio (16 / 9).
1年前
記事のアイキャッチ画像
Day 52: declaring multiple layer lists
Manuel Matuzović - Blog
On day 46, I’ve explained how you can order layers by defining them in a comma-separated list first. The first layer in the list has the lowest priority and the last layer the highest.@layer base, components, theme, framework;You can create as many lists as so you want, but the important thing to remember is that layers are stacked based on the order in which they first appear. If you define one layer in multiple lists, only the first appearance of that layer matters.@layer base, components, theme;@layer framework, base, components;@layer base { p { border: 10px solid red; }}@layer framework { p { border-color: blue; }}@layer components { p { border-color: rebeccapurple; }}@layer theme { p { border-color: green; }}Although components is the last layer in the last list and therefore should have the highest priority, the color of the border is blue, as defined in the framework layer. That’s because base and components have already been defined earlier. @layer base, components, theme;@lay
1年前
記事のアイキャッチ画像
Day 53: disabling pull-to-refresh
Manuel Matuzović - Blog
On day 47, I introduced you to the overscroll-behavior property, and I showed you how to use it to disable scroll-chaining. There’s another feature we can disable using this property.In some mobile browsers, you can refresh the page by swiping down when the page is scrolled to the very top. That's called pull-to-refresh. This is a great feature, but depending on what the user’s interacting with on the page, this can be undesirable.You can use overscroll-behavior: none; to disable pull-to-refresh.html, body { overscroll-behavior: none;}You have to put it on <html> and <body> because in Chrome it only works on the <body> and in Safari only on the <html> element (tested on Android 12 Chrome, FF, Samsung Internet and Safari 16 on iOS).Please don't disable this feature by default, only when it's beneficial to your users.My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 54: testing for the support of a selector
Manuel Matuzović - Blog
Support for a CSS property isn’t the only thing you can check with @supports(), you can also check support for a selector.I knew you can check whether a property is supported by the current browser and apply styles accordingly. @supports selector(:has(a)) {<div hidden class="grid"> Your browser supports <code>display: grid</code> 🎉</div>@supports (display: grid) { .grid { display: block }}display: grid 🎉What I didn’t know is that you can do the same, but for a selector using the selector() function.<div hidden class="has"> Your browser supports <code>:has()</code> 🎉</div>@supports selector(:has(a)) { .has { display: block }}:has() 🎉You can also reverse the query.@supports not selector(:has(a)) { /* You're Firefox, Opera Mini, etc. fallback */}My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 55: anonymous layers
Manuel Matuzović - Blog
In all previous posts about cascade layers I’ve used named layers in the demos, but it’s actually not required to name them.Using @layer without a name works just as well. The downsides are that you can’t append styles elsewhere in the document to the same layer and you can’t define a custom order since you don’t have a name to reference them.@layer { p { border: 10px solid red; }}@layer { p { border-color: rebeccapurple; }}You can also import style sheets into an anonymous layer by using the layer keyword.@import url('style.css') layer;My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 56: container queries
Manuel Matuzović - Blog
You can use media queries to style elements based on features of the browser viewport, for example, min-width, max-height, or orientation. With container queries, you can now do the same but with any parent element. Instead of the viewport, you can now listen to properties and features of a containing element.You can query all kinds of things, not just the width, height, or orientation, but for example custom properties, as well. There’s an important difference between size container features (width, height, inline-size, block-size, aspect-ratio, orientation) and style container features (computed values). If you want to query size container features, you have to define a size container explicitly. That’s because they require special size containment in order to function. Miriam Suzanne explains it in Use the Right Container Query Syntax like that:Normally, the size of an element would be based on the size of its contents – but if we query that size, and change the contents based on th
1年前
記事のアイキャッチ画像
Day 57: media queries: range syntax
Manuel Matuzović - Blog
With CSS Media Queries Level 4, it's possible to use mathematical comparison operators in media queries.Instead of (min-width: 768px) you can now write (width >= 768px).Before@media(min-width: 768px) { body { background-color: aqua; }}After@media(width >= 768px) { body { background-color: aqua; }}Before@media(min-width: 400px) and (max-width: 800px) { body { border: 40px dotted yellow; }}After@media(400px <= width <= 800px) { body { border: 40px dotted yellow; }}My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Restart
Manuel Matuzović - Blog
Like many others, I’ve been thinking a lot about Twitter, social media in general, and what being on a social media platform means for me.The other day I logged into Twitter with my HTMHell account and I looked at the feed. It was full of opinions by “tech personalities” (men), funny tweets, and random videos. It felt like being on Reddit or 9gag. That’s not the reason I’m on social media. To be fair, it mostly showed recommended tweets because I only follow 3 accounts (React, Vue, and Angular. Funny, right?), but others told me that their feeds are full of NFT and crypto spam and Musk’s brain farts, too.Looking at the Twitter timeline again after a month of being on Mastodon made me realize just how fucked up Twitter is. So much superficial, attention seeking and useless crap driven by the urge for more and more engagement fueled by a harmful algorithm. This form of social media is not good for us. And it’s not just Twitter, Instagram and TikTok aren’t any better. The other day I saw
1年前
記事のアイキャッチ画像
Day 58: ordering nested layers
Manuel Matuzović - Blog
On day 43, we've learned how to group layers and on day 46, how to order them. In this post, we’ll look into ordering grouped layers.If we take the following layer, the background color of the <p> will be red because the last defined layer has precedence over previously defined layers.@layer base { @layer reset { p { background-color: #fff; } } @layer theme { p { background-color: aqua; } } @layer defaults { p { background-color: red; } }}yo!We can change the order by defining the layers within the base layer upfront.@layer base { @layer reset, defaults, theme; @layer reset { p { background-color: #fff; } } @layer theme { p { background-color: aqua; } } @layer defaults { p { background-color: red; } }}reset has the lowest priority and theme the highest.yo!If we move the list outside of the base layer, our custom order has no effect because the layers in the list only exist inside the base layer.@layer reset, defaults, theme;@layer base { @layer reset { p { background-color: #fff; } } @
1年前
記事のアイキャッチ画像
Day 59: naming containers
Manuel Matuzović - Blog
When you add a container query, it will look for the nearest ancestor container, by default. If you have multiple nested containers or if you just want to make sure that your query uses the right container, you can name containers and query them specifically.Let's say, we have 2 size containers, .wrapper and <section>.<div class="wrapper"> <section> <h2>Latest news</h2> <div class="card"> <h2>Hey, I'm a card!</h2> </div> </section></div>/* That's our outer size container. */.wrapper { container-type: inline-size;}/* That's our inner size container. */section { width: 50%; container-type: inline-size;}/* Default styles for the card. */.card { background-color: yellow; border: 5px solid;}/* Container query */@container (min-width: 500px) { .card { background-color: hotpink; }}By default, the container query watches the width of the closest size container, <section>. You can grab and resize the <section> by clicking and dragging it in the bottom right corner. The background color of the .
1年前
記事のアイキャッチ画像
Day 60: the ::part() pseudo-element
Manuel Matuzović - Blog
You can use the ::part CSS pseudo-element to style an element within a shadow tree.Let's have a look at the following web component.There's a heading and a paragraph in the shadow DOM and we can pass content via light DOM.class NewsTeasers extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); this.shadowRoot.innerHTML = ` <h3>Latest news</h3> <p>Here's a selection of our latest blog posts.</p> <slot></slot> ` }}customElements.define('news-teasers', NewsTeasers);<news-teasers> <ol> <li><a href="#1">Blog post 1</a></li> <li><a href="#2">Blog post 2</a></li> <li><a href="#3">Blog post 3</a></li> <li><a href="#4">Blog post 4</a></li> </ol></news-teasers>Latest newsHere's a selection of our latest blog posts. ` }}customElements.define('news-teasers', NewsTeasers);class NewsTeasers2 extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); this.shadowRoot.innerHTML = ` Latest newsHere's a selection of our latest blog posts. ` }}customElemen
1年前
記事のアイキャッチ画像
Day 61: color-scheme
Manuel Matuzović - Blog
The color-scheme property allows you to indicate which color schemes an element can be rendered in.This post is inspired by Sara Wallén’s article “Do you know color-scheme?” in the HTMHell advent calendar 2022. Read it to learn more about the feature and other ways of using it.If you create an HTML document, it comes with default styles that are more or less the same in most browsers. A serif font, transparent (white) background, black text color, etc. You could say that the default theme for any HTML document is a light theme because it uses a light background color. Now here comes the big revelation (at least to me) Sara writes about: There's also a dark theme.The thing is, if you change the color mode in your operating system from dark to light, the colors in the browser’s viewport stay the same (If you know of an operating system (OS)/browser where that's different, please tell me). You have to instruct the browser first about what to do. You can do that by using the color-scheme p
1年前
記事のアイキャッチ画像
Day 62: the container shorthand
Manuel Matuzović - Blog
On day 56 you've learned that you have to define a container-type when working with size containers and on day 59 you've learned that you can name containers using the container-name property.The container shorthand allows you to define both properties in a single property, [name] / [type].section { container: wrapper / inline-size; /* Same as: container-name: wrapper; container-type: inline-size; */}If you only define a single value (the name), the type is normal by default.section { container: wrapper; /* Same as: container-name: wrapper; container-type: normal; */}My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 63: explicit defaulting with inherit, initial, unset, and revert
Manuel Matuzović - Blog
There are several CSS-wide property values you can use to specify a particular defaulting behavior for a property explicitly.Okay, okay, I know, these keywords aren't new at all, except for revert maybe which is newish, but if I want to write about revert-layer, which is brand new, I need a basic understanding of all keywords. Also, I had the feeling that most of you, like me, don't know what all of these keywords do, and I was right. At least, if you want to trust this poll on Mastodon.Our baselineWe'll work with the following example. We have a <div> with a 1px solid green border, a red text color, and a 10px margin. Nested in the div is a <h2> with a blue text color.<div> <h2>standard</h2></div>div { color: red; border: 1px solid green; margin: 10px;}h2 { color: blue;}Feliz NavidadNow, let's apply keywords to the border, color, and margin property on the <h2> and see what happens. inherith2 { border: inherit; color: inherit; margin: inherit;}inherit is pretty straight-forward. The <
1年前
記事のアイキャッチ画像
Day 64: the revert-layer keyword
Manuel Matuzović - Blog
With cascade layers comes a new CSS-wide property value, revert-layer.You can use the revert-layer keyword to roll back the cascade to a value defined in a previous layer.In the following example, the base layer defines a black color for the border. The theme layer sets the border color to fuchsia. In a print media query within the theme layer we revert the style back to the color in the base layer.@layer base { h2 { --border-color: #000; border: 4px solid var(--border-color); }}@layer theme { h2 { --border-color: fuchsia; } @media print { h2 { --border-color: revert-layer; } }}<h2>Sretan Božić!</h2>Sretan Božić!If you try to print this page, you will see that the border-color of the <h2> is #000.Preview print stylesheetMy blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 65: using the em unit in container queries
Manuel Matuzović - Blog
Relative units used in container queries work differently than relative units in media queries.If you use em in a media query, the font-size of the <body>, <html>, or any other element on the page doesn't matter. That's because relative length units in media queries are based on the initial value, which means that units are never based on results of declarations. em in a media query is relative to the font-size, defined by the user agent or the user’s preferences./* The font size of both <body> and <html> is 40px, the media query doesn't fire at 2560px (40 * 64), but at 1024px (16 * 64) (assuming that the base font size in the browser is 16px).*/html, body { font-size: 40px;}@media (min-width: 64em) { body { background: aqua; }}With container queries that's different. Relative length units are evaluated based on the computed values of the query container.The container query in the following example fires at 512px (32 * 16 = 512) because the font size of the container is 16px.section {
1年前
記事のアイキャッチ画像
Day 66: individual transform properties
Manuel Matuzović - Blog
From now on you can transform elements with the translate, rotate, and scale properties.Let’s say you apply several transforms to an element, and on :hover and :focus you only want to change one of them, for example, scale.<button>Transform</button>button { transform: translateX(20px) rotate(15deg) scale(1); }button:is(:hover, :focus) { transform: scale(2); }TransformThat doesn't work as expected because by setting transform: scale(2) you're overwriting all the previously defined transforms. To fix that, you have to repeat the other transforms.button { transform: translateX(20px) rotate(15deg) scale(1); }button:is(:hover, :focus) { transform: translateX(20px) rotate(15deg) scale(2); }TransformThat can cause a lot of repetition in your code.Individual transform properties fix that issue because now you can use translate, rotate, and scale separately.button { translate: 20px 0; rotate: 15deg; scale: 1; }button:is(:hover, :focus) { scale: 2; }TransformMy blog doesn't support comments yet,
1年前
記事のアイキャッチ画像
Day 67: counting children
Manuel Matuzović - Blog
There are a lot of interesting things you can do with the :has() pseudo-class. I’ve already covered some of them on day 26.If you want to style an element based on the number of direct children it has, you can do that with just CSS.:has() pseudo-class with the condition that it has a direct child item that is a third child.Note: Firefox doesn't support :has() yet.ul:has(>:nth-child(3)) { border: 10px solid red;}:nth-child(3)) { border: 10px solid red; } A B A B C A B C D If you want to limit the rule to only apply styles if the list contains exactly three items, you extend the condition and only select the <ul> if it contains a direct child item that is the third and last item.ul:has(>:nth-child(3):last-child) { border: 10px solid red;}:nth-child(3):last-child) { border: 10px solid red; } A B A B C A B C D My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 68: cascade layers and browser support
Manuel Matuzović - Blog
Cascade layers are one of the most interesting and useful additions to CSS recently. It will change the way we write CSS, how we use selectors, naming conventions, and probably also more things that I can’t think of right now.If you’re as excited about using cascade layers as I am, you have to consider browser support before you get started.Browser supportAll major desktop browsers started supporting cascade layers between February and April 2022, but your users might use an older version of Safari, IE11, or one of the mobile browsers that doesn’t support it yet.Feature queriesWhen you use cascade layers in a browser that doesn’t support them, styles in your layers will be ignored entirely. Only unlayered styles will be applied. I was trying to figure out a way to serve styles only to browsers that don’t support layers in order to provide some kind of basic fallback styling for them, but I had no luck.There is a @supports feature in CSS that will allow us to test for support of @layer
1年前
記事のアイキャッチ画像
Day 69: width in container queries
Manuel Matuzović - Blog
In a media query, it’s obvious what width means. It always refers to the width of the viewport. With size container queries it’s not that obvious./* Kicks in when the viewport has a minimum width of 500px */@media (min-width: 500px) { body { background-color: hotpink; }}width in a size container query queries the width of the container's content box. Let me illustrate what that means with an example.The <section> is the container and the .card changes background color when the container has a minimum width of 500px.<section> <h2>Latest news</h2> <div class="card"> <h2>Hey, I'm a card!</h2> </div></section>The <section> has an explicit width, padding, and a border. Its box-sizing property is set to the default value content-box.section { box-sizing: content-box; container-type: inline-size; width: 500px; padding: 20px; border: 10px solid;}@container (min-width: 500px) { .card { background-color: hotpink; }}The total width of the container (<section>) is 560px (500px width + 40px padding
1年前
記事のアイキャッチ画像
Day 70: the defined pseudo-class
Manuel Matuzović - Blog
:defined represents any element that has been defined. This includes standard elements and custom elements that have been successfully defined. [data-sample] :defined { background-color: #000; color: #fff;} class BasicComponent extends HTMLElement { constructor() { super(); }}customElements.define('de-fined', BasicComponent);:defined { background-color: #000; color: #fff;}Standard elements<p>I'm defined</p><small>I'm defined</small>I'm definedI'm definedUndefined custom elements<unde-fined>I'm not defined</unde-fined>I'm not definedDefined custom elements<de-fined>I'm defined</de-fined>class BasicComponent extends HTMLElement { constructor() { super(); }}customElements.define('de-fined', BasicComponent);I'm definedDeprecated elements <center>test</center> <font>test</font> <blink>test</blink>test test testMy blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 71: the masonry keyword
Manuel Matuzović - Blog
The masonry keyword allows you to create masonry grid layouts.If you want to create a masonry layout, all you have to do is turn one of the grid axes into a masonry axis using the masonry keyword.<ol> <li> <a href="/blog/2023/100daysof-day70/"> Day 70: the defined pseudo-class </a> </li> <li> <a href="/blog/2022/100daysof-day69/"> Day 69: width in container queries </a> </li> <li> <a href="/blog/2022/100daysof-day68/"> Day 68: cascade layers and browser support </a> </li> …</ol>ol { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(16.5rem, 1fr)); grid-template-rows: masonry;}This simple layout turns into……this “so much better” layout.You can also turn the other axis into the masonry axis.ol { display: grid; gap: 1rem; grid-template-columns: masonry; grid-template-rows: repeat(auto-fill, 6rem);}AccessibilityBy default, the packing algorithm puts items into the column with the most space. This may cause a disconnect between DOM and tabbing order, which can be an
1年前
記事のアイキャッチ画像
A year in review: 2022
Manuel Matuzović - Blog
I started my last year in review post with the words “2021 was wild!”. If 2021 was wild, then I don’t know what 2022 was because so much stuff was going on last year.PersonalOur daughter was born in 2021, and suddenly she’s 19 months old. It’s killing me how fast time flies. It’s still amazing to watch her grow and learn new things. Looking at photos from early last year baffles me because she looks so different. It’s almost like I’m looking at another or multiple other persons. I’m really glad that I managed to find enough time for her. I still don’t work on weekends and evenings and I try to be home early every day, which allows me to spend a lot of time with her.Some of my personal highlights this year were a weekend trip to Italy (Venice and Chioggia), our 4 week trip to Greece (Peloponnese and Athens), our road trip to Germany and The Netherlands (Freiburg, Utrecht, Rotterdam, Amsterdam), and of course moving to Graz. In early 2022, we were looking for a house or flat in Graz, the
1年前
記事のアイキャッチ画像
Day 72: the masonry-auto-flow property
Manuel Matuzović - Blog
If you’re creating a masonry layout, the packing algorithm puts items into the column with the most space by default. This can cause accessibility issues. The masonry-auto-flow property gives us control over the automatic placement of items in a masonry layout.In the following layout, you can see how the tile for “Day 63” is placed in the middle column. Since day 64 is in the last column of the first row, you’d expect day 63 to be in the first column of the second row. If you compare the heights of the items in the first column, you can see that the middle column is the one with the most available space. That’s why the algorithm placed day 63 there. ol { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(16.5rem, 1fr)); grid-template-rows: masonry;}It’s hard to orientate and understand how the layout is structured, if the placement is completely random. By setting masonry-auto-flow to next, we can instruct the browser to place items one after the other on the gri
1年前
記事のアイキャッチ画像
Day 73: size container features
Manuel Matuzović - Blog
In my previous posts about size container features I’ve only used the min-width feature, but there’s actually more you can query.container-type: inline-size establishes size containment only on the inline axis. There is no block-size option because it wasn’t possible for browsers to implement, but there is a size option, which establishes size containment on both dimensions of the container. According to Miriam Suzanne, you should be careful using this option because I may cause side effects, but it allows you to query more than just the width/inline-size.orientationYou can query the orientation of the container. If the height is larger than the width, the orientation is portrait. If the width is larger than the height, it's landscape..container { border: 8px solid aqua; container-type: size; width: 10rem; height: 15rem;}.container2 { width: 15rem; height: 10rem;}.child { aspect-ratio: 1; width: 5rem; border: 4px solid; color: red;}@container (orientation: portrait) { .child { backgrou
1年前
記事のアイキャッチ画像
Day 74: using !important in cascade layers
Manuel Matuzović - Blog
In order to understand how !important works in cascade layers, you have to understand how !important works generally. The conclusion of this post might not be what you expect. .sample1 h1 { color: green; } .sample1 h1 { color: red; } .sample2 h1 { color: green !important; } .sample2 h1 { color: red; } @layer base { .sample3 h1 { color: green; } } @layer components { .sample3 h1 { color: red; } } .sample4 h1 { color: blue; } @layer base { .sample4 h1 { color: green; } } @layer components { .sample4 h1 { color: red; } } .sample5 h1 { color: blue; } @layer base { .sample5 h1 { color: green !important; } } @layer components { .sample5 h1 { color: red; } } .sample6 h1 { color: blue; } @layer base { .sample6 h1 { color: green !important; } } @layer components { .sample6 h1 { color: red !important; } } .sample7 h1 { color: blue !important; } @layer base { .sample7 h1 { color: green !important; } } @layer components { .sample7 h1 { color: red !important; } }The basicsLet's start nice and easy.
1年前
記事のアイキャッチ画像
Day 75: font palettes
Manuel Matuzović - Blog
Apparently, multicolored typefaces on the web are a thing. You can use and modify them in CSS.@font-face { font-family: 'Rocher'; src: url('/blog/2023/100daysof-day76/RocherColorGX.woff2');}@font-palette-values --pink { font-family: 'Rocher'; base-palette: 1;}@font-palette-values --green { font-family: 'Rocher'; base-palette: 2;}@font-palette-values --gray { font-family: 'Rocher'; base-palette: 9;}[data-sample] h1 { font-family: 'Rocher'; font-size: 6rem; margin: 0;}.sample2 h1 { font-palette: --pink;}.sample3 h1 { font-palette: --green;}.sample4 h1 { font-palette: --gray;}@font-face { font-family: 'Rocher'; src: url('/fonts/RocherColorGX.woff2');}h1 { font-family: "Rocher";}woah!Pretty cool, right? What’s even cooler is that color fonts come with a default color palette and optionally with a set of alternative palettes that you can access via CSS.The font “Rocher” comes with 11 palettesIn order to use a different palette, you have to reference and associate it with a font using the @f
1年前
記事のアイキャッチ画像
Day 76: overwriting colors in font palettes
Manuel Matuzović - Blog
You can use the override-colors property to override colors in a font palette.Color fonts come with one or more predefined color palettes. You can select them by using the font-palette property. You can also define your own color palettes or change specific colors in a palette using the override-colors property.@font-face { font-family: 'Rocher'; src: url('/fonts/RocherColorGX.woff2');}h1 { font-family: "Rocher";}That's the default font palette of the “Rocher” font.Jurassic 5Using the @font-palette-value rule you can create a new font palette. You reference the typeface you want to create the palette for using the font-family property. Color palettes of the “Rocher” font consist of 4 colors. We can override colors by defining the index (starting with 0) of the color and a valid color value.@font-palette-values --custom { font-family: 'Rocher'; override-colors: 0 #a13908;}h1 { font-palette: --custom;}The PharcydeYou don't have to start at 0, you can override any color.@font-palette-valu
1年前
記事のアイキャッチ画像
Day 77: block-size, inline-size, vi, and vb
Manuel Matuzović - Blog
There are logical properties for width and height values.width and heightThe logical alternative for width is inline-size and the alternative for height is block-size. Here’s an example of how using inline-size over width makes a difference.If you use width, the property sets the physical width, regardless of the writing mode.h1 { border: 1rem solid; padding: 1rem; width: 16rem;}.vertical { writing-mode: vertical-rl;}<h1>width horizontal</h1><h1 class="vertical">width vertical</h1>width horizontalwidth verticalIf you use inline-size, the property sets the logical width with respect to the writing mode.h1 { border: 1rem solid; padding: 1rem; inline-size: 16rem;}.vertical { writing-mode: vertical-rl;}inline-size horizontalinline-size verticalvi and vbThere are also logical unit alternatives for vw and vh.The width and height of the <div> is always the width and height of the viewport, regardless of the writing mode.div { border: 1rem solid; width: 20vw; height: 40vh;}.vertical { writing-
1年前
記事のアイキャッチ画像
Day 78: container query units
Manuel Matuzović - Blog
Container queries come with their own units. [data-sample] div { outline: 10px solid; overflow: auto; margin: 1rem; } .sample2 div { container-type: inline-size; } [data-sample] h2 { background-color: yellow; border: 5px solid; padding: 1rem; margin: 1rem; inline-size: 80cqi; }Container query units work the same as viewport units. 80cqi equals 80svi. div { outline: 10px solid; } h2 { background-color: yellow; border: 5px solid; inline-size: 80cqi; }It's me, Mike D!The big difference is that if they're inside a size container, container query units aren't relative to the viewport anymore, but to the container. div { outline: 10px solid; container-type: inline-size; } h2 { background-color: yellow; border: 5px solid; inline-size: 80cqi; }It's me, Mike D!Container Units unit relative to cqw 1% of a query container’s width cqh 1% of a query container’s height cqi 1% of a query container’s inline size cqb 1% of a query container’s block size cqmin The smaller value of cqi or cqb cqmax The l
1年前
記事のアイキャッチ画像
CSS color functions and custom properties
Manuel Matuzović - Blog
I know I’m really late to the party, but I finally understood why people find color functions like hsl(), hwb(), or lab() so appealing.There are many reasons, but one of them is that in combination with custom properties, working with color functions is so much easier, cleaner, and understandable compared to working with hex colors or rbg().Here's an example. Let's say we have a simple status component.[role="status"] { --background-color: rgb(211 232 248); background-color: var(--background-color); padding: 1rem; margin-block-end: 1em;}<div role="status"> <strong>Information:</strong> You're logged in as “Tyler Durden”.</div>Information: You're logged in as “Tyler Durden”.If I wanted to add a border to the component with a slightly darker variation of the background color, I would usually take the color picker in dev tools and just pick a random darker color.[role="status"] { --border-color: rgb(122 186 235); border: 2px solid var(--border-color);}Information: You're logged in as “Tyl
1年前
記事のアイキャッチ画像
Day 79: font-tech() and font-format()
Manuel Matuzović - Blog
You can use the @supports rule to check whether a browser supports a specified font technology or font format.font-tech()The font-tech() function checks whether a browser supports the specified font technology. For example, you can apply styles only if the browser supports font-palettes or if it doesn't support incremental font loading (I have no idea what that is).<div class="palette" hidden> Your browser supports font palettes 🎉</div><div class="incremental" hidden> Your browser doesn't support incremental font loading 😭</div>@supports font-tech(palettes) { .palette { display: block; }}@supports not font-tech(incremental) { .incremental { display: block; }}Your browser supports font palettes 🎉Your browser doesn't support incremental font loading 😭You can find a list of font technologies on MDN.font-format()The font-format() function checks whether a browser supports the specified font format. For example, you can apply styles only if the browser supports.woff2.<div hidden> Your b...
1年前
記事のアイキャッチ画像
Day 80: container style queries
Manuel Matuzović - Blog
Container style queries allow querying the computed values of a query container.No browser supports it yet, but we should be able to do something like this:.card { aspect-ratio: 1 / 1;}.card--wide { aspect-ratio: 16 / 9}@container style(aspect-ratio: 16 / 9) { img { object-fit: cover; }}We can check whether a container has a specific property and value assigned and apply additional styles based on this condition. Chrome support container style queries behind a flag, but only with custom properties, not ordinary properties.Here’s an example based on a component I've built a while ago where this can be useful. We have a card component that can be used in different ways. It can contain just text, text and an image, text and a video, and also text with a background color. Most background colors in our design system work well with black as the text color, but there’s one exception.:root { --nebelgrau: #d6d1ca; --flieder: #aaaafa; --abendstimmung: #49274b;}.card { --bg: var(--nebelgrau); bac
1年前
記事のアイキャッチ画像
Day 81: the order of individual transform properties
Manuel Matuzović - Blog
On day 66, I’ve introduced you to individual transform properties. An interesting detail about these properties is the order in which transforms are applied compared to the transform property.If you use the transform property, transformation functions are applied in the order of appearance, from left to right.<button class="button1">Button 1</button><button class="button2">Button 2</button>.button1 { transform: translateX(50px) scale(1.5); }.button2 { transform: scale(1.5) translateX(50px); }Button 1Button 2With individual transform properties, the order of appearance of the declarations doesn’t matter. The order is always the same: translate –> rotate –> scale..button3 { translate: 50px 0; scale: 1.5; }.button4 { scale: 1.5; translate: 50px 0;}Button 3Button 4If you mix transform and individual properties, individual transforms get applied first..button5 { transform: translateX(50px); scale: 1.5;}.button6 { transform: scale(1.5); translate: 50px 0;}Button 5Button 6My blog doesn't supp
1年前
記事のアイキャッチ画像
Day 82: value processing
Manuel Matuzović - Blog
This post differs from most of the other posts because it’s not about modern CSS, but about CSS fundamentals. When I was writing about custom properties and especially about container style queries, I realized that I had to understand some of the basics of the language first before I could comprehend how certain properties and rules worked.The final value of a property in CSS is the result of a multi-step calculation. In this process, the actual value of a property can come from different sources, take on different forms, and undergo adjustments.Declared ValuesA property may have multiple declared values. Each property declaration applied to an element contributes a declared value.h1 { color: aqua;}#heading { color: rebeccapurple;}.heading { color: fuchsia;}The color property has 3 declared values. The cascade takes theses values and chooses a single “winning” value, the cascaded value.Cascaded ValueThe cascaded value represents the result of the cascade. It’s the declared value with t
1年前
記事のアイキャッチ画像
Day 83: computed values in container style queries
Manuel Matuzović - Blog
On day 80, I’ve explained that we can check whether a container has a specific property and value assigned and apply additional styles based on this condition. On day 82, I’ve explained that the value of a property can come from different sources, undergo adjustments before it becomes the actual value, and take on different forms along the way. To use container style queries, it’s important to understand which value's being used in queries.Let’s start nice and easy. We have a .card and the value of the --bg property is red. In a style query, we check if that’s actually the case and apply conditional style to the <h1> nested in the card.<div class="card"> <h1>heyho</h1></div>.card { --bg: red;}@container style(--bg: red) { h1 { border: 10px dotted aqua; }}Result: the <h1> gets a beautiful dotted border.If we put the color value in its own property and query the assignment of the var() function to the --bg property, the styles will be applied, as well.html { --color-red: red;}.card { --b
1年前
記事のアイキャッチ画像
Day 84: the @property at-rule
Manuel Matuzović - Blog
The @property rule allows you to register custom properties.You can already define custom properties, but the difference between defining and registering is that the at-rule allows you to specify the type and other attributes.@property --hue { /* The type. */ syntax: '<angle>'; /* Is it an inhertiable property? */ inherits: false; /* The initial value. */ initial-value: 0deg;}syntaxThe syntax descriptor specifies the syntax (or type) of the property. You can find a list of supported syntax component names in the spec.@property --milliseconds { syntax: '<integer>'; inherits: false;}inheritsThe inherits descriptor specifies whether the property inherits from its parent or not.@property --color-primary { syntax: '<color>'; inherits: true;}initial-valueThe initial-value descriptor specifies the initial value of the custom property.@property --color-primary { syntax: '<color>'; inherits: true; initial-value: rgb(0 0 0);}An exampleLet's say we have a <button> and we want to transition the ba
1年前
記事のアイキャッチ画像
Day 85: typed custom properties in container style queries
Manuel Matuzović - Blog
Registering typed custom properties can be useful in container style queries.The following container style query matches because the computed value of both --bg and --color is “red”.html { --color: red;}.card { --bg: red;}/* Condition is true, styles applied */@container style(--bg: var(--keyword)) { h1 { border: 10px dotted fuchsia; }}What's important to understand is that we're comparing two strings, not colors. If we change --color to rgb(255 0 0), the query doesn't match anymore.html { --color: rgb(255 0 0);}.card { --bg: red;}/* Condition is false, styles not applied */@container style(--bg: var(--color)) { h1 { border: 10px dotted fuchsia; }}That's where the @property rule comes into play. It allows us to add a type to a custom property and turn --bg into a proper color value.@property --bg { syntax: '<color>'; inherits: true; initial-value: rgb(0 0 0);}html { --color: rgb(255 0 0);}.card { --bg: red;}/* Condition is true, styles applied */@container style(--bg: var(--color)) { h
1年前
記事のアイキャッチ画像
Day 86: the initial-letter property
Manuel Matuzović - Blog
The initial-letter property specifies size and sink for initial letters.@supports (-webkit-initial-letter: 1) or (initial-letter: 1) { p::first-letter { -webkit-initial-letter: 3; initial-letter: 3; }}The property takes two arguments. The first one defines the size of the initial letter in terms of how many lines it occupies. The optional second argument defines the number of lines the initial letter should sink. If it's omitted, it equals the initial letter size. p::first-letter { initial-letter: 2; }1 as the second argument indicates a raised initial. p::first-letter { initial-letter: 2 1; }Values greater than 1 indicate a sunken initial letter. p::first-letter { initial-letter: 2 5; }Note: This property is currently only supported in Safari with a prefix, but it's coming to Chromium browsers soon.My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Day 87: mask properties
Manuel Matuzović - Blog
You can use mask properties to apply a mask to an element. .post img { border: none; } .mask { -webkit-mask-image: url(/blog/2023/100daysof-day87/htmhell_logo.svg); mask-image: url(/blog/2023/100daysof-day87/htmhell_logo.svg); } .mask-size { -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; } .element { max-width: 400px; aspect-ratio: 1; background-color: red; -webkit-mask-image: url(/blog/2023/100daysof-day87/htmhell_logo.svg); mask-image: url(/blog/2023/100daysof-day87/htmhell_logo.svg); -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; }Let's say you have an image and a logo. You can use the logo to mask the image.img { mask-image: url(/images/htmhell_logo.svg);}There are a bunch of properties you can use to adjust the styling of the mask.mask-clip (MDN)mask-composite (M
1年前
記事のアイキャッチ画像
Day 88: CSS Motion Path
Manuel Matuzović - Blog
CSS Motion path allows you to position any graphical object and animate it along a specified path. .square { background: hsl(93deg 75% 49%); height: 2em; width: 2em; position: absolute; inset-inline-start: 0; inset-block-start: 0; } .sample2 .square { offset-path: path("m4,139c0,-1.31731 7.78207,-137 121.62162,-137c113.83955,0 85.71428,133.04808 178.37837,127.12019"); } .sample3 .square { offset-distance: 30%; } .sample4 .square { offset-rotate: 13deg; } .sample5 .square { animation: move 2s infinite; animation-play-state: paused; } [aria-pressed="true"] ~ div .square { animation-play-state: running; } [aria-pressed="true"] { outline: 4px solid green !important; } @keyframes move { 0% { offset-distance: 0%; } 100% { offset-distance: 100%; } } .sample6 .square { position: static; } .sample6 .demo-wrapper { height: 150px; } .demo-wrapper { position: relative; }Let's you have a path, and you want to animate an element along that path. Note: You don't need the <svg> to achieve that, but fo
1年前
記事のアイキャッチ画像
Day 89: higher-order custom properties
Manuel Matuzović - Blog
Style queries may change the way we write CSS significantly.Caution: If you’re a fan of Tailwind or similar utility frameworks, you might find this post offensive because it suggests using fewer classes instead of more.On day 80 I’ve introduced you to container style queries. I’ve showed you a practical example from a project I was working on where style queries would’ve been really useful: When the following component has a dark background color, I set a light text color on all children.<div class="card"> <h2>light</h2></div><div class="card" style="--bg: var(--dark)"> <h2>dark</h2></div>:root { --dark: #000; --light: aqua;}.card { --bg: var(--light); background-color: var(--bg); color: #000;}@container style(--bg: var(--dark)) { * { color: #fff; }}Yeah, I know, not the best example in the world, but you get the point.What’s even more interesting than querying custom properties, we’ve applied to a property of a container, is querying custom properties whose sole purpose it is to tell
1年前
記事のアイキャッチ画像
Day 90: scoped styles in container queries
Manuel Matuzović - Blog
Rules within a container query only apply to descendants of that container.If you write a media query and you put rules in the media block, the rules apply to the entire document.Apply rules@media (min-width: 1024px) { * { outline: 4px solid }}If you write a container query and you put rules in the container block, the rules only apply to descendants of the container.<div data-sample="demo"> <h2>A quote</h2> <blockquote>“What came first – the music or the misery? Did I listen to the music because I was miserable? Or was I miserable because I listened to the music? Do all those records turn you into a melancholy person?”</blockquote></div>[data-sample] { container-type: inline-size;}@container (min-inline-size: 240px) { * { border: 8px dotted fuchsia; }}Apply rulesA quote“What came first – the music or the misery? Did I listen to the music because I was miserable? Or was I miserable because I listened to the music? Do all those records turn you into a melancholy person?”If you have nest
1年前
記事のアイキャッチ画像
Day 91: a previous sibling selector with :has()
Manuel Matuzović - Blog
I’ve already shown much appreciation for the :has() pseudo-class in this series, but that we can use it as a previous sibling selector tops it all of.Since this is not an official selector, but more something like a hack, it can be hard to read and interpret. So, let’s start nice and easy.We have three buttons. If we hover/focus one button and we want to highlight it and the next adjacent button in the DOM at the same time, we can use the adjacent sibling selector. button { outline-width: 8px; outline-offset: 4px; outline-color: hotpink; } button:is(:hover, :focus-visible) { outline-style: solid; } button:is(:hover, :focus-visible) + button { outline-style: dashed; }previous middle nextThere's no previous item selector, but using :has() we can select an item that comes before another item. I've written about next-sibling combinators and :has() on day 26. Here’s an example from that post: The following code sets the block-end margin of all <h2> to 0 if they're followed by a <time> eleme
1年前
記事のアイキャッチ画像
Day 92: relative color syntax
Manuel Matuzović - Blog
With the relative color syntax we can modify existing colors using color functions. If an origin color is specified, each color channel can either be directly specified, or taken from the origin color and modified.For example, we can take a HEX color and add opacity using the rgb() color function and the from keyword.div { --color: #FF0000;}div { background-color: rgb(from var(--color) r g b / 50%);}rgb(255 0 0 / 50%)Or we can take the color and replace a specific channel.div { background-color: rgb(from var(--color) r g 150);}rgb(255 0 0 / 50%)We can even use the calc() function.div { background-color: hsl(from var(--color) h s calc(l - 10%));}hsl(0deg 100% 40%)We can use channel keywords in their corresponding argument, but we don't have to. We can use them in any position.div { background-color: rgb(from var(--color) calc(r * .3 + g * .59 + b * .11) calc(r * .3 + g * .59 + b * .11) calc(r * .3 + g * .59 + b * .11));}rgb(30% 30% 30%)How cool is that!? Is there a catch? Well, yeah, it
1年前
記事のアイキャッチ画像
Day 93: the lch() color function
Manuel Matuzović - Blog
The lch() color function allows you to pick colors from the CIELAB color space, which is device-independant and covers the entire gamut (range) of human color perception.Currently, the CSS colors we can define are in the sRGB color space. For the longest time, professional monitors weren’t able to display all possible colors in this range. So, using sRGB colors was absolutely sufficient, but that’s not true anymore. Nowadays, monitors can display much more colors than exist in the sRGB color space. With lch() we get access to these colors (currently Safari 15+ only).The function takes 3 space-separated values.div { background-color: lch(78% 172.33 248.2);}l - lightnessThe first value defines the lightness. It's typically a number between 0% (representing black) and 100% (representing white). It's typically a number between 0% and 100% because the value can exceed 100% up to 400% representing extra-bright whites on some systems. It's the same lightness as in the lab() color function. di
1年前
記事のアイキャッチ画像
Day 94: the accent-color property
Manuel Matuzović - Blog
The accent-color CSS property allows us to specify the accent color for user-interface controls generated by an element.Yeah, I know, yet another property that isn’t new at all, but Safari added support only recently (in 15.4) and I’ve never used it. Reason enough for me to include it in the series.We can use the property to change the accent color of radio buttons, check boxes, progress elements and range sliders. Here's how the look like by default. You can see how the color automatically varies in a dark color scheme to work better with dark background colors. * { flex: 1 0 0; min-width: 16rem; padding: 1rem; } .dark-scheme { background-color: hsl(0 0% 0%); color: #FFF; color-scheme: dark; } .accent { --l: 40%; accent-color: hsl(270deg 50% var(--l)); } .sample3 .dark-scheme { --l: 75%; }.dark-scheme { background-color: hsl(0 0% 0%); color: #FFF; color-scheme: dark;}DefaultCheckboxRadioRange Default dark schemeCheckboxRadioRange We can change that color by setting the accent-color pr
1年前
記事のアイキャッチ画像
Day 95: the color-mix() function
Manuel Matuzović - Blog
The color-mix() function takes two colors and returns the result of mixing them, in a given color space, by a specified amount.To mix colors, pass the in keyword, followed by the color space, and 2 colors.body { background-color: color-mix(in srgb, blue, white);}The syntax is pretty straightforward, but the result is not so much. At least for someone like me who doesn’t understand color and color on the web very well. What surprised me specifically is that mixing colors in different color spaces can yield very different results.:root { --color1: blue; --color2: white;}.a { --bg: color-mix(in srgb, var(--color1), var(--color2)); }.b { --bg: color-mix(in srgb-linear, var(--color1), var(--color2)); }.c { --bg: color-mix(in hsl, var(--color1), var(--color2)); }.d { --bg: color-mix(in hwb, var(--color1), var(--color2)); }.e { --bg: color-mix(in lch, var(--color1), var(--color2)); }.f { --bg: color-mix(in oklch, var(--color1), var(--color2)); }.g { --bg: color-mix(in lab, var(--color1), var(
1年前
記事のアイキャッチ画像
Day 96: the margin-trim property
Manuel Matuzović - Blog
The margin-trim property allows a container element to trim the margins of its children where they adjoin the container’s edges.Let’s say we have a parent element and 4 children, and we use margin-block-end to add some spacing between these elements.<ul> <li>A</li> <li>B</li> <li>C</li> <li>D</li></ul>li { margin-block-end: 1rem;}A B C D That’s great, but to avoid the extra space at the end of the list, we want to make sure that the last item doesn’t get any margin. To achieve that, I’ve used at least 3 different solutions in the past.Apply a margin on all elements and remove it from the last. li { margin-block-end: 1rem; } li:last-child { margin-block-end: 0; }Apply a margin on all elements but the last. li:not(:last-child) { margin-block-end: 1rem; }Use the lobotimized owl selector ul > * + * { margin-block-start: 1rem; }There are pros and cons to all solutions. Anyway, eventually we might not have to use any of them when we have this specific problem because margin-trim solves it mo
1年前
記事のアイキャッチ画像
Day 97: animating grids
Manuel Matuzović - Blog
It’s possible to animate gap, grid-template-columns, and grid-template-rows.Almost 6 years ago I wrote a blog post on CodePen titled “Animating CSS Grid Layout properties”. A lot has changed since then, especially recently, and I wanted to update the post, but the blogging feature on CodePen has been sunset and I can’t edit the post anymore. Since animating grids is topical again, I added it to the series. According to the CSS Grid Layout Module Level 1 specification there are 5 animatable grid properties:grid-gap, grid-row-gap, grid-column-gapgrid-template-columns, grid-template-rowsAnimating these properties will most likely affect larger areas of the screen. That's why it's important to only show animation to those who have no preference for reduced motion..grid { --col: 9.5rem; --row: 8rem; --gap: 2rem; display: grid; grid-template-columns: repeat(3, var(--col)); grid-template-rows: repeat(4, var(--row)); grid-gap: var(--gap);}.grid--full { --col: 30%; --row: 4rem; --gap: 1rem;}@me
1年前
記事のアイキャッチ画像
Day 98: oklab() and oklch()
Manuel Matuzović - Blog
oklab() and oklch() are okay versions of lab() and lch() because lab() and lch() are not okay.I will not pretend that I really understand this whole color on the web thing, how it works or why one color function offers many more options to developers than the other, but I did learn several things during this experiment. I understand why a color function like hsl() offers better DX than rgb(). I’ve learned that rgb(), hsl(), and hwb() use colors from the sRGB color space, and lab() and lch() colors from the CIELAB color space. These color functions are relevant now because they support more colors and modern monitors can display them. It kinda also makes sense to me why some people say that using lch() is more intuitive than lab().This doesn’t sound too bad, but as soon as I dig deeper into colors, I soon reach a point where I’m out. It’s usually a graph or complicated formula that stops my enthusiasm. Why am I saying this? I don’t know, maybe self-defense, maybe to make you feel better
1年前
記事のアイキャッチ画像
Day 99: native nesting
Manuel Matuzović - Blog
Nesting in CSS is coming soon! For me personally not the killer feature, at least compared to cascade layers or container queries, but still exciting. Let’s see how it works.The most important thing to know about native nesting in CSS is that the nested selector always must start with a symbol (. # : [ * + > ~) because of limitations in browser parsing engines.The following code doesn't work:/* Doesn't work */ul { li { border-color: green; }}To work around that limitation the nested selector can start with an &.ul { & li { border-color: green; }}/* Same as: ul li { } */Besides this limitation, everything works as expected for me. Here are some of the things I've tested:a { &:hover { background-color: aqua; } &:focus-visible { background-color: aqua; }}/* Same as: a:hover { } a:focus-visible { } */a { &:is(:hover, :focus-visible) { background-color: aqua; }}/* Same as: a:is(:hover, :focus-visible) { } */h2 { font-family: sans-serif; &::first-letter { color: red; }}/* Same as: h2 { } h2:
1年前
記事のアイキャッチ画像
Why I'm not the biggest fan of Single Page Applications
Manuel Matuzović - Blog
Sometimes it seems like accessibility experts and other web professionals hate JavaScript. This might be true for some, but most understand that JavaScript can be useful for improving UX and even accessibility. JavaScript solutions are often more accessible than their pure HTML or CSS counterparts.We know JavaScript is not an enemy, but, admittedly, there is a certain reluctance towards building client-side rendered websites by some developers. These people are often dismissed as the “old guard” because of their seemingly irrational aversion towards modern web development. If you don’t understand where this is coming from, it might seem incomprehensible why someone would not want to build single page applications (SPA), but go for the standard way of building websites, sometimes referred to as multi page applications (MPA), instead. There has been a lot of criticism about SPAs and especially React recently. On a personal level, I can absolutely understand that. I don’t like Meta and th
1年前
記事のアイキャッチ画像
Day 100: it's over, or is it!?
Manuel Matuzović - Blog
OMG, I did it, day 100! 4 months and 16 days ago I published the first post and then I wrote another post every workday for 138 days straight without missing a single day. In this final post, I want to do a quick recap and give an outlook for what's coming next.RecapStarting this project was one of the best and worst ideas I ever had. It was a great idea because I’m finally up to date with modern CSS. I’ve learned so so much, not just about the fancy new stuff, but also about CSS in general. Based on the feedback I’ve received, I wasn’t the only one who benefited from this project. This format, short, focused posts about a single topic, worked well for many people. That makes me happy. Thank you for reading and participating!It was a bad idea because it was so much work and it put quite a lot of pressure on me at times. Each post took me at least 1 hour to write, sometimes up to 4 hours. In some weeks, that meant spending an entire working day or more writing these posts on top of my o
1年前
記事のアイキャッチ画像
My CSS wish list
Manuel Matuzović - Blog
I know I’m late to the party, but there are a few things on my CSS wish list I haven’t seen on others, so I thought I’d share.Visually hidden contentI'd love to see a native implementation of visually hidden text. I’m not the biggest fan of hiding stuff only for some, but it’s inevitable sometimes.Instead of this:.visually-hidden { clip-path: inset(50%); height: 1px; overflow: hidden; position: absolute; white-space: nowrap; width: 1px;}I want this:.visually-hidden { visibility: visually-hidden;}Or another example:.skip-link { position: absolute; visibility: visually-hidden;}.skip-link:focus-visible { visibility: visible;}Alternative text for pseudo elementsIt would be great if I could exclude generated content from the accessibility tree or give it an accessible name.button::before { content: "c"; font-family: MyIconFont; alt: "";}There is actually an implementation in some browsers that looks like this:label:has(+[required])::after { content: '★' / 'required';}Or even better:label:ha
1年前
記事のアイキャッチ画像
50.1% empty links
Manuel Matuzović - Blog
The new WebAim 1 Million report was recently published, and the results are sobering. Compared to the previous year, 0.5% fewer websites contained automatically detectable accessibility issues, but the total number of erroneous websites is still 96.3%.The number of empty links increased by 0.4% from 49.7% to 50.1%. More than half of the websites tested contained empty links (links with no text).To give you an idea of how this affects the user experience and accessibility, I tested the following empty links with screen readers.<a href="https://webaim.org/projects/million/"> <img src="/images/screenshot-04-03-23_copy.jpg"></a>Here's what different screen readers announce using the Tab key on desktop and touch on mobile.Linked image with no alt Screen reader Browser Result NVDA Firefox million, graphic, link JAWS Firefox H T T P S colon slash slash webaim dot org slash projects slash million slash JAWS Edge images slash screenshot dash 04 dash 03 dash 23 underline copy, link, graphic Talk
1年前
記事のアイキャッチ画像
It's very likely that…
Manuel Matuzović - Blog
I repeatedly see certain bad practices in HTML that ironically contain clues for implementing them properly in their class names or in the way they're built. In this evergreen post, I collect them.…if you're using javascript:void(0) as the value of the href attribute, the element you're actually looking for is <button>. <a href="javascript:void(0);"> Open modal</a>More accessible alternative:<button> Open modal</button>ExplanationThe role of <a> is link and the role of <button> is button. Users have certain expectations when they find an element. A general rule of thumb: Use a link if it takes you somewhere else. Use a button if you submit a form or run JavaScript.My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
Invalid at computed-value time
Manuel Matuzović - Blog
I rewatched Lea Verous’s talk about custom properties recently and learned something I missed the first time I watched it.A declaration of a custom property can be invalid at computed-value time, if its value is invalid. Depending on the property’s type, this results in the property being set to unset, so either the property’s inherited value or its initial value, depending on whether the property is inherited or not.That’s confusing, I know; here’s an example to better understand why it’s essential to know that.If we select a button and set its border and background to an invalid value, nothing happens to the button. The browser just throws away the entire declaration.button { border: bla; background: bla;}testIf we do the same but now put the invalid value in a custom property instead, the button looks different because the custom property is invalid at computed-value time and falls back to unset, which for background and border means initial since they're not inherited properties.bu
1年前
記事のアイキャッチ画像
details/summary inconsistencies
Manuel Matuzović - Blog
Scott O'Hara wrote a fantastic blog post about the details and summary elements last year. He explains that there are a lot of oddities and inconsistencies, and he backs his statements with detailed testing.To better understand the extent of these oddities and inconsistencies, I did my own testing (not as detailed as Scott's), and here's what I found:Announcements are very different across different screen readers/browsers. It goes from little information (“show more” in VoiceOver on iOS) to too much information (“Right pointing triangle, Show more, collapsed, summary, group” in Firefox on macOs)Removing or changing the triangle doesn’t seem to affect any screen reader/browser pairing except Firefox with all tested screen readers.Voice Over macOS Chrome/Edge/Arc, Voice Over macOS Safari, and Talkback Android Chrome provide the most consistent experience.Voice Over iOS Safari is also very consistent but in a bad way. It doesn’t announce any role or state.Details only expands in Chrome,
1年前
記事のアイキャッチ画像
Workshop: Deep Dive on Accessibility Testing
Manuel Matuzović - Blog
Once again I’ve teamed up with my friends at Smashing Magazine 😻 to share with you everything I know about web accessibility testing! In this smashing workshop we’ll talk about automatic and manual testing, screen reader basics, Single Page Applications, Dev Tools, and more.Sounds interesting? Great! Here are some more details about the workshop:What you will learn in this workshopWhich testing tools are available and most commonly used.How to assess the accessibility of a component or page.The difference between automatic and manual testing.How to use automatic accessibility testing tools and how to interpret the results.How to use the keyboard to discover accessibility bugs.Screen reader basics and how to use them for accessibility testing, both on desktop and mobile devices.How to test the accessibility of Single Page Applications.Common pitfalls of Single Page Applications and how to avoid them.How to integrate accessibility testing in your day-to-day development workflow.Running ...
1年前
記事のアイキャッチ画像
Deleted files in a freshly cloned git repo
Manuel Matuzović - Blog
The other day someone emailed me and told me that they tried to clone the HTMHell repo, but they only got an empty folder (except for the hidden .git folder), and all files were deleted as if they cloned the repo and immediately moved all files into the trash. li { margin: 0 !important; }I couldn't reproduce the issue on my Mac, but I had the same problem on my Windows machine. This post on StackOverflow suggested that it was related to using forbidden characters in file names. Forbidden characters in file names on Windows:< (less than)> (greater than): (colon)" (double quote)/ (forward slash)\ (backslash)| (vertical bar or pipe)? (question mark)* (asterisk)I reviewed the files and found an image named 30-bullet-"list".png. I have a node script that automatically creates the social media preview images for blog posts and uses the title as the file name. I forgot to take care of special characters.I tweaked the script and renamed the file, and – voilà – cloning now works as expected on
1年前
記事のアイキャッチ画像
CSS! CSS! CSS!
Manuel Matuzović - Blog
I just came home after three beautiful days in Amsterdam, where I gave a talk at the CSS Day conference. I’ve watched many inspirational and engaging presentations and had many interesting conversations. My biggest takeaway: The CSS community needs you!First things first: CSS Day is a wonderful event, and the community is lovely. If you can, consider attending it!Adam Argyle was the MC on the first day, and after every talk, he chanted, “CSS! CSS! CSS!“. It was silly but funny. It was Adam’s way of showing appreciation for how far we’ve come with the language and how powerful it is.After the first day, I was chatting about CSS in a bar with some friends. Stephan said it’s great that browsers are shipping so many new features, but we need people to use them in real projects, share their experiences in talks and articles, and show the world what CSS is capable of.That’s where I ask you a favour: Please write more about CSS. Show us what you’ve built and how you build it. The CSS communit
1年前
記事のアイキャッチ画像
Syntax podcast episode 623: “Nothing in CSS” errata
Manuel Matuzović - Blog
I just listened to the Syntax podcast for the first time because they were discussing topics near and dear to my heart, HTML and CSS. The episode is called “Nothing in CSS - 0 vs 0px, no, none, hidden, initial and unset”, and they’re talking about all the things that can be 0, none, or hidden in CSS and HTML. Super interesting stuff, but unfortunately, they got some things wrong. The don‘t have a comment section, so I’m commenting on the episode here in case someone else gets confused by their misinformation.Disclaimer: I don't want to shame them; we're all humans and make mistakes, but their podcast reaches many people, and I feel like I can't keep their statements uncommented.4:15 visibility hidden and screen readersWes said, as opposed to display: none visibility: hidden is not hidden from screen readers and he suggested to add aria-hidden="true" to make sure these elements are hidden from screen readers.visibility: hidden already removes an element from the accessibility tree.4:35
1年前
記事のアイキャッチ画像
Day 101: scoping
Manuel Matuzović - Blog
Similar to container queries or cascade layers, we have another new impactful feature in CSS: scoping.Let's start nice and easy by reading the spec.A scope is a subtree or fragment of a document, which can be used by selectors for more targeted matching. More targeted matching sounds great. We can use the @scope rule to scope styles of a child to a parent selector.<div class="wrapper"> <div class="card"> <div class="content"> the cascade is unavoidable </div> </div></div>@scope(.card) { .content { border: 5px solid red; }}Okay, cool, but we could do that already, right? By combining selectors, we can scope a child to a parent..card .content { border: 5px solid red;}The biggest difference in this simple example is that the cascade prioritizes declarations with a more proximate scoping root, regardless of specificity or source order..card .content { background-color: green;}.wrapper .content { background-color: blue;}/* -> blue */In the following example, it's green because before the or
1年前
記事のアイキャッチ画像
Cascade Layers are useless*
Manuel Matuzović - Blog
*if you don‘t understand the problems they solve and use them in combination with other solutions that tackle the same challenges albeit less elegantly and with the downside of limiting you in taking full advantage of selectors, one of the coolest features in CSS, and if you ignore the fact that they can help you organise and manage your own and third-party code.I've heard several people say they've tried Cascade Layers but didn't see any changes, so they dropped them again. That can also easily happen to you when you structure your CSS in layers for the first time. I can explain why.Let's say we have three layers (base, components, and utility) and three rules, one in each layer. It doesn't matter whether you have 3, 30, or 300 rules. The underlying principle I'm trying to explain applies regardless of the size of your CSS.<label for="email"> E-Mail</label><input type="email" class="form__input--error u-no-shadow" aria-invalid="true" required id="email">@layer base { input { --_border
1年前
記事のアイキャッチ画像
form and search landmarks
Manuel Matuzović - Blog
I wanted to know how well common screen readers and browsers support search and form landmarks. Here are my results: table { table-layout: fixed; white-space: nowrap; } tbody td { background: green; color: #fff; } tbody th { font-weight: normal; /* position: sticky; left: 0;*/ } td.no { background: #bf0404; } th a:is(:link, :visited) { color: #fff; } th a:focus-visible { outline-color: currentColor; }Software/OS/browserNVDA 2023.1 with Firefox 114VoiceOver macOS 13.4.1 with Safari 16.5.1Talkback Android 13 with Chrome 114JAWS 2023.2212.13 with Edge 114Narrator Windows 10 with Edge 114VoiceOver iOS 15.7.7 with SafariI tested using the following shorcuts, commands and gestures.D key + Elements list in NVDARotor in VO iOSRotor + single key quick nav in VO macOSSwiping + landmark navigation in TalkbackR key + landmarks list (Insert + Ctrl + R in JAWSD key + Landmarks List in Narratorform roleSummary: You can use it, but forms won't be exposed as landmarks on VoiceOver and Talkback. To get
1年前
記事のアイキャッチ画像
the details element and in-page search
Manuel Matuzović - Blog
An important factor in terms of UX and accessibility for deciding whether the <details> element is the right solution for a problem is the find-in-page behaviour.In Chromium-based browsers, the details element automatically opens when it contains a string the user searches for.You can try it yourself in this demo.I often hear the question, “Can I use the details element for page navigation?”. My answer is always “No” for two main reasons:You probably don’t want your navigation to open randomly only because a user searched for a term on the page.There are still a lot of browser inconsistencies, and you want such an important part as the navigation for your site to work consistently and reliably.You can find more examples and details in Adrian Roselli's “Details / Summary Are Not [insert control here]”.My blog doesn't support comments yet, but you can reply via [email protected].
1年前
記事のアイキャッチ画像
the article element and screen readers
Manuel Matuzović - Blog
I wanted to know how and if common screen readers expose the <article> element.Summarytl;dr: shit's complicated.Some screen readers don't announce articles and have no default quick nav shortcuts. Some don't announce them but treat them as landmarks. Others announce them as articles and treat them as landmarks. There's no difference whether you label them or not.article element screen reader support results NVDA Jaws Voice Over (macOS) Narrator VoiceOver (iOs) Talkback Virtual Cursor/Swipe no yes yes no yes no Landmark list no no no no yes yes Custom article list no yes yes no yes no Default quick nav key no yes no no no no Demo code<article> <h2>Unlabelled</h2></article><article aria-labelledby="heading"> <h2 id="heading">Labelled by heading</h2></article><article aria-label="Labelled by attribute"> <h2>Labelled by attribute</h2></article>NVDA 2023.1 with Firefox 114NVDA doesn't announce the article's role when you use the arrow keys or list it in the elements list. You can add a cust
1年前
記事のアイキャッチ画像
O dialog focus, where art thou?
Manuel Matuzović - Blog
Here’s a job interview question for you: When you click a button and call the showModal() method to open a modal <dialog>, where does the focus go by default, and how can you move it elsewhere?Don't know the answer? Neither did I, so I tested it.OS/BrowsersmacOs 13.4.1 VenturaHere’s a Codepen with all demos so you can follow along.Demo 1: Dialog with no interactive element<button>demo 1</button><dialog> <h1>Demo 1</h2></dialog>document.addEventListener('click', e => { if (e.target.closest('button')) { e.target.nextElementSibling.showModal() }})Focus is on:Chrome: dialogbodybody Demo 2: Dialog with interactive elements<button>demo 2</button><dialog> <h1>Demo 2</h2> <button>First focusable element</button> <a href="#">Last focusable element</a></dialog>Focus is on:Chrome: first focusable elementfirst focusable elementfirst focusable element Demo 3: Dialog with interactive elements and close button first<button>demo 3</button><dialog> <form method="dialog"> <button>close</button> </form>
10ヶ月前
記事のアイキャッチ画像
Visually hidden links with 0 dimensions
Manuel Matuzović - Blog
If you have used a visually-hidden class in the past, you might have noticed that the width and height is set to 1px and not 0. I’ve always wondered why.Even in James Edwards’ “The anatomy of visually-hidden” I didn’t find the answer because he wasn’t sure either.While testing a client’s site a few minutes ago, I found at least one good reason./* A typical .visually-hidden class */.visually-hidden { clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; overflow: hidden; position: absolute; white-space: nowrap; width: 1px;}.skip-links a:not(:focus) { overflow: hidden; width: 0; height: 0; padding: 0; border: 0; margin: 0;}.skip-links a:not(:focus) { overflow: hidden; width: 1px; height: 1px; padding: 0; border: 0; margin: 0;}So, there you go. That's why you want to keep the 1px height and width in your visually-hidden classes. You can test it in this CodePen.My blog doesn't support comments yet, but you can reply via [email protected].
10ヶ月前
記事のアイキャッチ画像
aria-haspopup and screen readers
Manuel Matuzović - Blog
I read Steve Faulkners “hasPopup hasPoop” where he mentions differences in what screen readers announce when dealing with the aria-haspopup attribute. I wanted to know how that manifests used on a button. table { table-layout: fixed; white-space: nowrap; } tbody td { background: green; color: #fff; } tbody th { font-weight: normal; /* position: sticky; left: 0;*/ } td.no { background: #bf0404; } td.kinda { background: #bf8504; } th a:is(:link, :visited) { color: #fff; } th a:focus-visible { outline-color: currentColor; }SummaryThe situation isn't too bad because all screen readers and browsers, except Narrator in Firefox and Chrome, at least support the attribute. Talback and NVDA don't support the grid, listbox, and tree values. NVDA also doesn't support dialog. Other than that, it works great. I noticed some interesting details:VoiceOver with Safari doesn't announce the aria-expanded attribute in combination with aria-haspopup on macOS and iOs.VoiceOver on MacOS with Firefox announce
9ヶ月前
記事のアイキャッチ画像
Pros and cons of using Shadow DOM and style encapsulation
Manuel Matuzović - Blog
When I started to work with web components, I compared different options and decided to go with lit. I knew the extra performance cost would pay off quickly, and it fit into my performance budget. I’m still happy with my decision. .pro { color: green; } .con { color: red; }I was new to web components and lit, so I had to consult the docs quite often. On the page about Shadow DOM it says: Rendering into children and not shadow DOM is generally not recommended. Your element will not have access to DOM or style scoping, and it will not be able to compose elements into its internal DOM.To affirm that, the Using shadow DOM page on MDN says:An important aspect of web components is encapsulation — being able to keep the markup structure, style, and behavior hidden and separate from other code on the page so that different parts do not clash, and the code can be kept nice and clean.That confirmed my perception of how web components work: they go hand in hand with Shadow DOM. I thought that's t
9ヶ月前
記事のアイキャッチ画像
Day 102: selecting the scoping root
Manuel Matuzović - Blog
There are different ways of selecting the scoping root inside a @scope rule.When you use the :scope pseudo-class in a stylesheet, it matches the :root element.:root { border: 10px solid red;}:scope { border-color: blue;}/* -> 10px blue border on the <html> element */When you use it inside a scope rule, it matches the rule's scoping root.<div class="wrapper"> <div class="content"> the cascade is unavoidable </div></div>@scope (.wrapper) { :scope { border: 5px solid red; }}/* -> 5px red border on the .wrapper element */Selectors inside a scope rule can only match elements that are in scope. Selecting .content within the .wrapper scope works:@scope (.wrapper) { .content { background: aqua; }}/* That's like writing .wrapper .content {} */Selecting .wrapper .content within the .wrapper scope doesn't work:@scope (.wrapper) { .wrapper .content { background: aqua; }}/* That's like writing .wrapper .wrapper .content {} */You can use :scope instead of .wrapper. That works because it doesn't matc
9ヶ月前
記事のアイキャッチ画像
New workshop: Advanced Modern CSS Masterclass
Manuel Matuzović - Blog
In my newest workshop I introduce you to the most useful modern features in CSS and show how you can implement them today in your code base to improve scalability, maintainability, and productivity.About the workshopclamp(), :is(), :where(), min(), max(), lab(), lch(), oklab(), oklch(), cascade layers, container queries, logical properties, :has(), svh, dvh, lvh, font-pallets, subgrid…How do you feel when you read these terms? Confused? Interested? Excited? Overwhelmed?2022 and 2023 were critical years for CSS. Browsers got together and began shipping new features week after week almost simultaneously. While that’s good news for us developers, keeping track of and adapting to those changes is challenging.In Advanced Modern CSS Masterclass, a brand new Smashing Magazine workshop, I introduce you to the latest and greatest features in CSS.What will you learn in this workshop?How to manage specificity with the help of cascade layers, :is(), and :where().New colour spaces and functions and
9ヶ月前
記事のアイキャッチ画像
Web Components Accessibility FAQ
Manuel Matuzović - Blog
I specialize in HTML and CSS, but I also write JS. Especially in the last year or so, I wrote quite a lot of JavaScript because we decided to port the front end of one of my clients to web components.When I first learned about web components, I had a lot of questions, especially regarding accessibility. While I found answers to many of them, I didn’t know everything I would’ve wanted to know. I wish I had a catalog of all the essential questions and answers when I started. That’s why I decided to design this post in a Q&A format. I’ll ask a question regarding the accessibility of web components, and then I’ll answer it.QuestionsMy blog doesn't support comments yet, but you can reply via [email protected].
8ヶ月前
記事のアイキャッチ画像
Mark all as read
Manuel Matuzović - Blog
I was on the train home from Hamburg when I decided to finally migrate my website from Netlify and 11ty to Kirby on my friend's server. I got most of the work done on the train and made some final changes on Monday.There's a lot you should consider when migrating from one tech stack to another. I didn't. I yoloed it, uploaded the site, and changed the DNS records, knowing there would be some damage. Is that smart? No. Did it work? Seems like it. At least, I didn't notice too much. There's only one thing: If you've subscribed to my site via RSS, you might see all of my ~200 posts as unread. I'm sorry. I've messed something up with the dates. Please ignore that and mark all posts as read. Thank you! Was it worth it? Yes, because now I'm one step closer to finally redesigning my site.If you notice anything else broken, please let me know via mail. ([email protected])My blog doesn't support comments yet, but you can reply via [email protected].
8ヶ月前
記事のアイキャッチ画像
Skip links on ikea.com
Manuel Matuzović - Blog
I am always pleasantly surprised when I find useful skip links. That's why I decided to collect examples here on my blog.I'll start with ikea.com. The first focusable element on every page is a skip link that allows you to skip the entire header, which makes sense because there are 15 interactive elements in it.Sidenote: I'm not sure why they set role="button" on the skip link because it's just an anchor link, and there doesn't seem to be any JavaScript involved. <a href="#hnf-content" role="button" class="hnf-skip-to-content hnf-btn hnf-btn--secondary"> <span class="hnf-btn__inner"> <span class="hnf-btn__label">Skip to main content</span> </span></a>Main skip link on ikea.comUpdate 13.10.23: The button role is gone now. Hours after I published this post, someone from the IKEA frontend team contacted me to tell me why they believed it was there. The next day, another person informed me that they'd removed it. Skål! 🔥There's another skip link right after the header, which allows you to...
7ヶ月前
記事のアイキャッチ画像
Day 103: the prefers-reduced-transparency media feature
Manuel Matuzović - Blog
Design trends like Glassmorphism use translucent backgrounds to create a specific visual effect, resulting in underlying background colors or elements shimmering through the background of the overlaying element. That may be visually appealing, but it can distract some people and impair legibility.Operating systems like macOS and Windows offer options to reduce transparency in the operating system.macOS: System settings - Accessibility - Display - Reduce transparency.iOS: Settings - Accessibility - Display - Reduce transparencyWindow: Settings - Ease of Access - Display - Show transparency in WindowsIn CSS, you can query that setting using the prefers-reduced-transparency media feature.dialog { background: rgba(255, 255, 255, var(--bg-opacity, 1)); backdrop-filter: blur(5px); border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 16px; box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);}@media(prefers-reduced-transparency: no-preference) { dialog { --bg-opacity: 0.2; }}Here's how the dialog
7ヶ月前
記事のアイキャッチ画像
Day 104: animation with registered custom properties
Manuel Matuzović - Blog
All major browsers except Firefox (coming soon!) support the @property at-rule. It enables you to do things you previously couldn't, like animating custom properties.Let's say you have two animations. One fades an element; the other moves it. Based on their motion preference, users see one or the other."; inherits: false; initial-value: 0; } @property --opacity3 { syntax: ""; inherits: false; initial-value: 1; } @keyframes move3 { from { --position3: 100vw; } to { --position3: 0; } } @keyframes fade3 { from { --opacity3: 0; } to { --opacity3: 1; } }.banner { --animation: fade; animation: var(--animation) 3s cubic-bezier(0.18, 0.89, 0.32, 1.28); } @media(prefers-reduced-motion: no-preference) { .banner { --animation: move; } } @keyframes move { from { translate: 100vw; } to { translate: 0; } } @keyframes fade { from { opacity: 0; } to { opacity: 1; } }Hello World! Replay { document.querySelector('.banner1').classList.remove('animate1') setTimeout(()=> { document.querySelector('.banner1'
7ヶ月前
記事のアイキャッチ画像
Totally remdom, or How browsers zoom text
Manuel Matuzović - Blog
Last week, I lied to my students. After I explained how the rem unit worked, I told them that they could compare px and rem by increasing the font size in their mobile browsers and see how it affects text zoom.Before I said that, we created a simple test page with two paragraphs and two rules. HTML<p class="px">Hello World!</p> <p class="rem">Hello World!</p>CSS.px { font-size: 16px;}.rem { font-size: 1rem;}Then, we opened the settings in Chrome, found the Appearance page, and changed the font size from medium to very large. The font size of the second paragraph, which uses rem, increased with the default font size in the browser. The first paragraph, which uses px, stayed the same.Other browsersYou can do the same in Firefox by visiting the General page in the browser settings, finding the Fonts section, and picking a font size larger than 16 in the size dropdown.In Desktop Safari, you can define a minimum font size under Settings - Advanced - Accessibility, but it doesn't make a diff
7ヶ月前
記事のアイキャッチ画像
Removing list styles without affecting semantics.
Manuel Matuzović - Blog
Some people, I guess primarily developers and not actual users, don’t like the fact that Safari removes list semantics of lists that don’t look like lists (list-style: none). Scott O’Hara provided a fix in “Fixing” Lists, where he suggests setting role="list" explicitly on the list to re-add list semantics. <ul style="list-style: none" role="list"> <li>…</li></ul>That works, but I found a way of removing list styles without affecting semantics.I learned in my post (lol) “Here’s what I didn’t know about list-style-type” that you can use a string as the value of the list-style-type property. Yesterday, I tried setting it to an empty string, and voilà, list style gone, semantics kept.ul { list-style-type: "";}A B C This “solution” probably needs thorough testing, but I get the same results as with the role solution in the following screen readers and browsers:VO with Safari on iOS 15.7.7Talkback with Chrome 118 on Android 13VO with Safari 16.5.2 on macOS 13.4.1NVDA 2023.2 with Firefox 119
6ヶ月前
記事のアイキャッチ画像
Day 105: defining multiple syntax components
Manuel Matuzović - Blog
As already explained on day 84, using the syntax descriptor, you can define the type of a custom property in an @property at-rule.@property --lh { syntax: '<number>'; inherits: false; initial-value: 1;}button { --lh: 1; line-height: var(--lh); transition: --lh 1s; width: min-content;}button:is(:focus-visible,:hover) { --lh: 2;}'; inherits: false; initial-value: 1;}@property --lhfixed { syntax: ' | '; inherits: false; initial-value: 1;}.button { --lh: 1; line-height: var(--lh); transition: --lh 1s; width: min-content;}.button1:is(:focus-visible,:hover) { --lh: 2;}.button2 { --lh: 16px;}.button2:is(:focus-visible,:hover) { --lh: 32px;}.button3 { --lhfixed: 16px; line-height: var(--lhfixed); transition: --lhfixed 1s;}.button3:is(:focus-visible,:hover) { --lhfixed: 32px;} Hello World That works well, but some properties, like line-height, support different types of values.If you use a length instead of a number, the transition doesn't work anymore because the provided value of the custom p
6ヶ月前
記事のアイキャッチ画像
Day 106: the scripting media feature
Manuel Matuzović - Blog
The scripting media feature is an excellent addition to CSS for those who believe in progressive enhancement: It enables you to detect whether scripting languages, such as JavaScript, are supported.If you disable Javascript in Firefox 117+, Chrome 120+, or Safari 17+ on this page, the disclosure widget below hides the button and displays the content instead. Detailed content goes here… { button.setAttribute('aria-expanded', button.getAttribute('aria-expanded') === "false")})CSS@media (scripting: enabled) { .disclosure-content { display: none; }}@media (scripting: none) { button[aria-expanded] { display: none; }}HTML<div class="disclosure"> <button aria-expanded="false"> Show details </button> <div class="disclosure-content" id="content"> <p>Detailed content goes here…</p> </div></div>JSconst button = document.querySelector('button');button.addEventListener('click', e => { button.setAttribute('aria-expanded', button.getAttribute('aria-expanded') === "false")})PS: Yes, I know, it's bette
6ヶ月前
記事のアイキャッチ画像
Not all automated testing tools support Shadow DOM in web components
Manuel Matuzović - Blog
There isn't much more to say; it's all in the title.Many automated testing tools are a collection of JavaScript functions you run on a page. Most of those rely on querying the DOM. If a tool doesn't consider shadow trees, it only catches accessibility errors in the Light DOM, which may give you a wrong sense of safety and potentially affect your users. tbody td { background: green; color: #fff; } td.no { background: #bf0404; } td.noish { background: #bf8504; }That's one more reason not to rely on automated testing only.That doesn't mean you shouldn't use automated testing if your site contains web components. You just have to ensure that the tool you're using supports them. A good way of doing that is creating a simple component that contains some accessibility bugs caused by nodes attached to the component's Shadow DOM, like the following component.<main> <h1 id="h1">Testing a11y bugs in web components</h1> <a href="#el">Jump to elem in shadow</a> <!-- Broken skip link --> <some-bugs>
5ヶ月前
記事のアイキャッチ画像
Workshop: Deep Dive on Accessibility Testing
Manuel Matuzović - Blog
Once again, I’ve teamed up with my friends at Smashing Magazine 😻 to share with you everything I know about web accessibility testing! In this smashing workshop we’ll talk about automatic and manual testing, screen reader basics, Single Page Applications, Dev Tools, and more.Sounds interesting? Great! Here are some more details about the workshop:What you will learn in this workshopWhich testing tools are available and most commonly used.How to assess the accessibility of a component or page.The difference between automatic and manual testing.How to use automatic accessibility testing tools and how to interpret the results.How to use the keyboard to discover accessibility bugs.Screen reader basics and how to use them for accessibility testing, both on desktop and mobile devices.How to test the accessibility of Single Page Applications.Common pitfalls of Single Page Applications and how to avoid them.How to integrate accessibility testing in your day-to-day development workflow.Running...
5ヶ月前
記事のアイキャッチ画像
My CSS wish list 2024
Manuel Matuzović - Blog
Following last year, I created a CSS wishlist for 2024.Before I get into the details, I have to say that creating a wishlist almost feels wrong because there are more features in CSS today than I could have ever wished for. So, I'd like to take this opportunity to thank everyone who contributed to CSS being where it is today: spec writers, invited experts, browser developers, everyone involved in Interop 202*, dev rels, bloggers, and people who report bugs and contribute to discussions about new and existing features. Thank you very much!Container Style QueriesWe need container style queries in all browsers. They will change how we write CSS and make our stylesheets more flexible, scalable, and robust. You can read why I believe that on the 12 Days of Web, or you can watch my talk from last year's CSS Day.Current support: Chrome/Edge 111+ScopeI understand how someone can be skeptical about the usefulness of scoping, but trust me, once you learn how it works and what it can do for you,
4ヶ月前
記事のアイキャッチ画像
beyond tellerrand: One of my favourite web development and design conferences
Manuel Matuzović - Blog
People often ask me for recommendations for front-end development conferences. Picking my Top 3 would be challenging, but I know that beyond tellerrand in Germany is one of them.Location in DüsseldorfWeb developers love the beyond tellerrand conference (BTConf), although the event isn't a typical web dev conf. The organizer, Marc Thiele, a lovely and special person, has a strong web dev background and affiliation. That's why many talks at his events are about HTML, CSS, and JavaScript. Still, there are always just as many or even more talks about typography, calligraphy, graphic design, creativity, leadership, and so much more. Last year, I saw a guy explain for 45 minutes how he tried to turn himself into a goat temporarily. Source: NPR / Princeton Architectural PressRecharging BatteriesI don't attend beyond tellerrand to learn technical things I can implement in my projects afterward. Although I have to say that I always learn something because the dev talks are usually excellent. I
1ヶ月前