Ads
Thursday, March 31, 2022
Partly Cloudy today!
With a high of F and a low of 33F. Currently, it's 42F and Clear outside.
Current wind speeds: 12 from the Southeast
Pollen: 0
Sunrise: March 31, 2022 at 06:37PM
Sunset: April 1, 2022 at 07:14AM
UV index: 0
Humidity: 41%
via https://ift.tt/rMy73CH
April 1, 2022 at 10:05AM
Wednesday, March 30, 2022
Snow Showers Early today!
With a high of F and a low of 22F. Currently, it's 30F and Cloudy outside.
Current wind speeds: 12 from the Northwest
Pollen: 0
Sunrise: March 30, 2022 at 06:38PM
Sunset: March 31, 2022 at 07:13AM
UV index: 0
Humidity: 89%
via https://ift.tt/rMy73CH
March 31, 2022 at 10:07AM
Tricks to Cut Corners Using CSS Mask and Clip-Path Properties
We recently covered creating fancy borders with CSS mask
properties, and now we are going to cut the corners with CSS mask
and clip-path
! A lot of techniques exist to cut different shapes from the corners of any element. In this article, we will consider modern techniques to create unique corner shapes while trying to work from reusable code that allows us to produce different results by adjusting variables.
Check this online tool to get an idea of what we are building. It’s a CSS generator where you select the shape, the corners, and the size then you get the code in no time!
We mainly have two types of cuts: a circular one and an angled one. For each, we can get the full shape or the border-only shape, not to mention that we can select the corners we want to cut. A lot of combinations!
Like in the previous article, we will make lots of use of the CSS mask
property. So, if you are not familiar with it, I recommend reading the quick primer I wrote before continuing.
Circular cut-out
For a circular or rounded cut, we will use radial-gradient()
. To cut four corners, the logical solution is to create four gradients, one for each corner:
Each gradient is taking a quarter of the element’s dimensions. The syntax of the gradient is self-explanatory:
radial-gradient(circle 30px at top left, #0000 98%, red) top left;
Translated, this renders a circle at the top-left corner with a 30px
radius. The main color is transparent (#0000
) and the remaining is red
. The whole gradient is also placed so that it starts at the element’s top-left corner. Same logic for the three other gradients. The keyword circle
can be omitted since we explicitly specified one value for the radius.
Like I did in the previous article, I will be using slightly bigger or smaller values this time around in order to avoid bad visual result. Here, I am using 98%
instead of 100%
to avoid jagged edges and 51%
instead of 50%
to create an overlap between gradients and avoid white spaces. This logic will follow throughout this article. In fact, you will find that adding or removing 1%
or 1deg
typically results in a nice visual.
We apply this to the CSS mask
property and we are done!
We can actually optimize that code a little:
--g: #0000 98%,#000;
--r: 30px;
mask:
radial-gradient(var(--r) at 0 0 ,var(--g)) 0 0,
radial-gradient(var(--r) at 100% 0 ,var(--g)) 100% 0,
radial-gradient(var(--r) at 0 100%,var(--g)) 0 100%,
radial-gradient(var(--r) at 100% 100%,var(--g)) 100% 100%;
mask-size: 51% 51%;
mask-repeat: no-repeat;
This way, we use custom properties for the redundant values and, as a personal preference, I am using numeric values for the positions instead of keywords.
In the generator, I will use the following syntax:
--g: #0000 98%,#000;
--r: 30px;
mask:
radial-gradient(var(--r) at 0 0 ,var(--g)) 0 0 /51% 51% no-repeat,
radial-gradient(var(--r) at 100% 0 ,var(--g)) 100% 0 /51% 51% no-repeat,
radial-gradient(var(--r) at 0 100%,var(--g)) 0 100%/51% 51% no-repeat,
radial-gradient(var(--r) at 100% 100%,var(--g)) 100% 100%/51% 51% no-repeat;
The shorthand syntax is easier to generate plus the whole value can be used as one custom property.
Can we use fewer gradients if we want?
Sure! One gradient can do the job. Hover the below to see the trick:
Here, we define one radial-gradient()
with no size (by default it is 100%
height and 100%
width). This gives us a hole in the center. We translate/move the gradient by half the width and height of the image to move the hole to one corner. Since, by default, the CSS mask repeats, we get the same on each corner. We have four cut corners with only one gradient!
The only drawback of this method is that we need to know the width and height of the element in advance.
Can’t we use -50%
instead of half the width and height?
Unfortunately, we’re unable to do that here because percentages doesn’t behave the same as pixel values when used with the CSS mask-position
property. They’re tricky.
I have a detailed Stack Overflow answer that explains the difference. It deals with background-position
but the same logic applies to the CSS mask-position
property.
However, we can use some tricks to make it work with percentage values and without the need to know the width or the height. When a gradient (or a background layer) has a width and height equal to the element, we cannot move it using percentage values. So we need to change its size!
I will define a size equal to 99.5% 99.5%
. I am reducing 0.5%
from the width and the height to have a value different from 100%
and at the same time keep the same visual result since we won’t notice a big difference between 100%
and 99.5%
. Now that our gradient has a size different from 100%
we can move it using percentage values.
I will not detail all the math, but to move it by half the width and the height we need to use this equation:
100% * (50/(100 - 99.5)) = 100% * 100 = 10000%
It’s a strange value but it does the job:
As you can see, the trick works just fine. Whatever the size of the element is, we can cut four corners using only one gradient. However, this method has a small drawback when the width or the height of the element is a decimal value. Here is an example with an image having a width equal to 150.5px
:
The use of 99.5%
combined with 150.5px
will create rounding issues that will break the calculation, resulting in the mask being misaligned. So, use this method with caution.
To overcome the rounding issue, we can combine the last trick with a pseudo-element. Here is a step-by-step illustration to understand the idea:
Here’s what going on in there:
- We define a pseudo-element that behaves as our background layer. Logically, we should use
inset:0
to make it cover the entire area, but we will create a small overflow by usinginset: -10%
meaning that the pseudo element will overflow each side by 10%. - We set our CSS mask to the pseudo-element. The mask size needs to match the size of the main element, not the pseudo-element. In other words, it will be smaller than the size of the pseudo-element and this is what we want to be able to move using percentage values. After we do the math, the size needs to be
100%/1.2
. Notice in the demo above that the CSS mask is within the green border so that it matches the size of the container. - Now, we need to move it in a way that simulates cutting the corner of the main element. The center of the hole needs to be in the corner of the main element, as illustrated in the demo. To do this, we use
mask-position: 300% 300%
(300% = 50%/(1 - 1/1.2)
). - We remove
no-repeat
to activate the repetition and get the same effect for every corner. - We clip the overflow and we get our final result!
I know it’s a bit overkill, but it does work and it requires only one gradient instead of four.
Let’s quickly recap the three methods we just covered:
- The first method uses four gradients and has no drawbacks as far as usage. Sure, it’s verbose but it works with any kind of element and size. I recommend using this one.
- The second method uses one gradient and works with any element, but it can break in some particular cases. It’s suitable with fixed-size elements. It’s ok to use, but maybe less frequently.
- The third method uses one gradient and requires a pseudo-element. It won’t work with
<img>
and other elements that unable to support a pseudo-element.
The generator only supports the first and third methods.
Now that we saw the case with all the corners, let’s disable some of them. Using the first method, any corner we want to keep uncut we simply remove its gradient and adjust the size of what remains.
To disable the top-right corner:
- We remove the top-right gradient (the blue one).
- We have an empty corner, so we increase the size of the red gradient (or the purple one) to cover that leftover space.
Done!
You probably see just how many possibilities and combinations we can do here. If we want to cut N
corners (where N
ranges from 1
to 4
), we use N
gradients. All we need is to correctly set the size of each one to leave no space.
What about the other methods where there’s only one gradient? We will need another gradient! Those two methods use only one radial-gradient()
to cut the corners, so we will rely on another gradient to “hide” the cut. We can use a conic-gradient()
with four sections for this task:
conic-gradient(red 25%, blue 0 50%, green 0 75%, purple 0)
We add it on the top of the radial gradient to get the following:
The conic-gradient()
covers the radial-gradient()
and no corner is cut. Let’s change one color in the conic-gradient()
to transparent. The one at the top-right, for example:
Did you see that? We revealed one corner of the radial-gradient()
and we end with one cut corner!
Now let’s do the same thing, but for the bottom-left corner.
I think you probably get the trick by now. By changing the colors of the conic-gradient()
from opaque to transparent, we reveal the corners we want to cut and gain all kinds of possible combinations. The same can be done with the third method.
Circular border-only cut-out
Let’s make the border-only version of the previous shape. In other words, we achieve the same shape but knock out the fill so all we’re left with is a border of the shape.
This is a bit tricky because we have different cases with different code. Fair warning, I will be using a lot of gradients here while finding opportunities to trim the number of them.
It should be noted that we will consider a pseudo-element in this case. Showing only the border means we need to hide the inner “fill” of the shape. Applying this to the main element will also hide the content — that’s why this is a nice use case for a pseudo-element.
One cut corner
This one needs one radial gradient and two conic gradients:
The first example illustrates the radial gradient (in red) and both conic gradients (in blue and green). In the second example, we apply all of them inside the CSS mask
property to create the border-only shape with one cut corner.
As the diagram shows, the radial-gradient()
creates the quarter of a circle and each conic-gradient()
creates two perpendicular segments to cover two sides. It should be noted that overlapping gradients is not an issue since we are not going to change the CSS mask-composite
property value.
Using the same code an adjusting a few variables, we can get the shape for the other corners.
Two cut corners
For the two-corner configuration we have two situations taking place.
In the first situation, there are two opposite corners where we need two radial gradients and two conic gradients.
The configuration is almost the same as cutting only one corner: we add an extra gradient and update a few variables.
In the second situation, there are two adjacent corners and, in this case, we need two radial gradients, one conic gradient, and one linear gradient.
“Wait!” you might exclaim. “How come the conic gradient covers three sides?” If you check the code, notice the repeat-y
. In all of the examples, we always used no-repeat
for the gradients, but for this we can repeat one of them to cover more sides and reduce the number of gradients we use.
Here is an example with only the conic-gradient()
to understand the repetition. The trick is to have a height equal to 100%
minus the border size so that the gradient fills that space when repeating, which covers the third side in the process.
Three cut corners
For this configuration, we need three radial gradients, one conic gradient, and two linear gradients.
Four corners cut
It takes four radial gradients and two linear gradients to cut all four corners.
I can hear you screaming, “How the heck am I supposed to memorize all these cases?!” You don’t need to memorize anything since you can easily generate the code for each case using the online generator. All you need is to understand the overall trick rather than each individual case. That’s why I’ve only gone into fine detail on the first configurations — the rest are merely iterations that tweak the initial foundation of the trick.
Notice there’s a general pattern we’ve been following throughout the examples:
- We add a
radial-gradient()
on the corners we want to cut. - We fill the sides using either a
conic-gradient()
or alinear-gradient()
to create the final shape.
It should be noted that we can find different ways to create the same shape. What I am showing in this post are the methods I found to be best after trying lots of other ideas. You may have a different approach you consider to be better! If so, definitely share it in the comments!
Angled cut-out
Let’s tackle another type of cut shape: the angled cut.
We have two parameters: the size and angle of the cut. To get the shape, we need a conic-gradient()
for each corner. This configuration is very similar to the example that kicked off this article.
Here is an illustration of one corner to understand the trick:
The difference between each corner is an extra offset of 90deg
in from
and the at
position. The full code is like below:
--size: 30px;
--angle: 130deg;
--g: #0000 var(--angle), #000 0;
mask:
conic-gradient(from calc(var(--angle)/-2 - 45deg)
at top var(--size) left var(--size),var(--g)) top left,
conic-gradient(from calc(var(--angle)/-2 + 45deg)
at top var(--size) right var(--size),var(--g)) top right,
conic-gradient(from calc(var(--angle)/-2 - 135deg)
at bottom var(--size) left var(--size),var(--g)) bottom left,
conic-gradient(from calc(var(--angle)/-2 + 135deg)
at bottom var(--size) right var(--size),var(--g)) bottom right;
mask-size: 51% 51%;
mask-repeat: no-repeat;
If we want to disable one corner, we remove the conic-gradient()
for that corner and update the size of another one to fill the remaining space exactly like we did with the circular cut. Here’s how that looks for one corner:
We can do the exact same thing for all the other corners to get the same effect.
In addition to CSS mask, we can also use the CSS clip-path
property to cut the corners. Each corner can be defined with three points.
The other corners will have the same value with an offset of 100%
. This gives us the final code with a total of 12 points — three per corner.
/* I will define T = [1-tan((angle-90)/2)]*size */
clip-path: polygon(
/* Top-left corner */
0 T, size size,0 T, /* OR 0 0 */
/* Top-right corner */
calc(100% - T) 0,calc(100% - size) size,100% T, /* OR 100% 0 */
/* Bottom-right corner*/
100% calc(100% - T),calc(100% - size) calc(100% - size), calc(100% - T) 100%, /* OR 100% 100% */
/* Bottom-left corner */
T 100%, size calc(100% - size),0 calc(100% - T) /* OR 0 100% */
)
Notice the OR
comments in that code. It defines the code we have to consider if we want to disable a particular corner. To cut a corner, we use three points. To uncut a corner, we use one point — which is nothing but the coordinate of that corner.
Border-only angled cut
Oof, we have reached the last and trickiest shape at last! This one can be achieved with either gradients or clip-path
, but let’s go with the clip-path
approach.
Things would get complex and verbose if we go with the gradient approach. Here’s a demo that illustrates that point:
There are nine gradients total, and I am still not done with the calculation. As you can tell, the thickness of the border is incorrect, plus the final result is unsatisfying due to the nature of gradients and their anti-aliasing issues. This approach might be a good exercise to push the limit of gradients, but I don’t recommend it in a production environment.
So, back to the clip-path
method. We will still wind up with verbose code, but less of a big deal since the generator can do the job for us with a cleaner end result.
Here is an overview of the path. I am adding a small gap to better see the different points but we should have an overlap of points instead.
The way we calculate the outer points is the same as how we did it for the regular angled cut. For the inner points, however, we need more math. Don’t worry, I’ll spare you some “boring” geometry explanation for this one. I know most of you don’t want it, but in case you need to dig into this, you can check the JavaScript file of the generator to find the code and the math I am using to generate the shape.
The 180deg
special case
Before we end, there’s a special case for the angle cut I want to call out. It’s where we use an angle equal to 180deg
. Here’s what that produces:
We have a straight line on the corner so we can optimize the clip-path
code. For the full shape, we can use eight points (two points per corner) instead of 12. And for the border-only version, we can use 18 points (nine inner points and outer points) instead of 26. In other words, we can remove the middle point.
The border-only shape can also be made using gradients. But rather than using nine gradients like we did before, we can get away with only four linear gradients and a clean result.
Conclusion
We just combined CSS masks with gradients to create some fancy shapes without resorting to hacks and a lot of code! We also experienced just how much it takes to strike the right balance of code to get the right results. We even learned a few tricks along the way, like changing values by one or even half a unit. CSS is super powerful!
But, as we discussed, the online generator I made is a great place to get the code you need rather than writing it out by hand. I mean, I went through all the work of figuring out how all of this works and I would likely still need to reference this very article to remember how it’s all put together. If you can memorize all of this, kudos! But it’s nice to have a generator to fall back on.
Tricks to Cut Corners Using CSS Mask and Clip-Path Properties originally published on CSS-Tricks. You should get the newsletter.
from CSS-Tricks https://ift.tt/85FR3tb
via IFTTT
Tuesday, March 29, 2022
Rain/Snow/Wind Early today!
With a high of F and a low of 25F. Currently, it's 34F and Cloudy/Wind outside.
Current wind speeds: 26 from the Northwest
Pollen: 0
Sunrise: March 29, 2022 at 06:40PM
Sunset: March 30, 2022 at 07:12AM
UV index: 0
Humidity: 87%
via https://ift.tt/JGKlN1Y
March 30, 2022 at 10:05AM
Monday, March 28, 2022
Partly Cloudy today!
With a high of F and a low of 43F. Currently, it's 54F and Clear outside.
Current wind speeds: 18 from the Southeast
Pollen: 0
Sunrise: March 28, 2022 at 06:41PM
Sunset: March 29, 2022 at 07:11AM
UV index: 0
Humidity: 45%
via https://ift.tt/gj0rUWt
March 29, 2022 at 10:05AM
6 Useful Bookmarklets to Boost Web Development
A bookmarklet is a JavaScript-based bookmark that adds to a web browser. I’d like to show you some awesome web browser hacks to aid your web development workflow and how to convert those hacks into time-saving bookmarklets.
- Activating design mode
- Applying a background to everything
- Simulating events
- Setting cookies
- Toggling classes
- Color widget bookmark
- What other bookmarklets can you think of?
Activating design mode
Design mode (styled as designMode
since it’s a JavaScript property) is for who like to experiment with variations of copy on a live website. For example, copywriters who like to observe how content reads within the flow of the website’s design, or, say, designers who want to ensure that text fits comfortably within a certain space at a certain font size.
JavaScript has a mightily simple feature that can render an entire HTML document editable. It works exactly like HTML’s contenteditable="true"
name-value attribute (or contentEditable="true"
in JavaScript) but for the whole document. If you’d like to see how it works, start by entering the browser’s console using the relevant keyboard shortcut:
- Chrome: Option + ⌘ + J / Shift + CTRL + J
- Firefox: Option + ⌘ + K / Shift + CTRL + K
- Safari: Option + ⌘ + C / Shift + CTRL + C
Next, type document.designMode="on"
into the console, hit Return, and then click on any text element. You’ll see that this text element (and all other text elements) are now editable simply by clicking on them. This method of editing text on a live website is much faster than having to open DevTools, then right-clicking and selecting the “Edit Text” option… and much less tiresome.
While I’m not sure that “design mode” is the most accurate description of the feature, it’s super useful nonetheless and it’s actually been around for a really long time, surprisingly.
And what’s even an even faster way to enable it? A bookmarklet, of course! Create a bookmark using javascript: document.designMode="on";void 0;
as the URL.
Applying a background to everything
When HTML elements don’t have backgrounds, it can be difficult to visualize their bounds and/or accurately measure the distance between them and other elements. Developers might want to better visualize bounds when dealing with optical imbalance (i.e. when something “looks off” even though it’s not), margin collapse (when certain margins are ignored), various issues with display:
/float:
/position:
, and more.
Applying backgrounds means applying a semi-transparent background to all HTML elements in order to better visualize their bounds and spacings. It’s something many of us commonly do by opening up DevTools then typing a CSS declaration like selector { background: rgb(0 0 0 / 10%); }
into the “Styles” box. But again, it’s really tiresome and repetitive — and something we can simplify with a bookmarklet.
Once again, to create a bookmark, we’re going to make a URL. Here’s what we can use for this one:
javascript: document.querySelectorAll("*").forEach(element => element.style.background="rgb(0 0 0 / 10%)");
We’re using a semi-transparent background because the transparency stacks, which ensures that every nested element is distinguishable and the distances between them can be measured.
Simulating events
Have you ever had to test a web event that first requires a series of interactions, or certain conditions to be met? It’s super time-consuming to have to test or debug these kinds of functionalities. This event simulation bookmarklet can be used to instantly trigger specific events, making testing a breeze.
Simulating an event means coding a “throwaway” button that triggers a JavaScript event, making it much easier to quickly and repeatedly test the event without having to meet any usual user-facing conditions, like needing to be logged in.
Assuming that you have your JavaScript event listeners set up, create a bookmark for each event that you’d like to trigger/simulate and submit the following URL:
javascript: document.querySelector("SELECTOR").click();
Replace “SELECTOR” with your unique selector, replace “click” with “focus” or “blur” (when necessary), or extend the snippet to make it trigger more complex events, like scroll.
Setting cookies
Cookies are tokens that are stored on a website visitor’s computer by the website that they’re visiting. Cookies contain data that can be read by the website that created them until they’ve exceeded their expiration date or have been deleted. The mere existence of a cookie can determine whether or not a visitor is logged in, whereas the data itself can store user information.
An example of a scenario where you might want to set a cookie using a bookmarklet is when you want to force a logged-in state during website testing. Websites often look very different for users that are logged in, however, logging in and out eventually becomes very tedious, so this bookmarklet can save quite a bit of time.
Manually writing expires=
dates for cookies is awkward as heck, but luckily this create-your-own-set-cookie-bookmarklet app can generate a bookmarklet for a specific cookie, if you know its exact name.
Toggling classes
You may want to add or remove a class from an HTML element in order to trigger a fresh state or a change in appearance, otherwise known as toggling classes. Class toggling happens behind the scenes of most live websites, but it can also be used during testing to skip having to meet certain user-facing conditions.
Class toggling can be used to trigger changes in appearance (e.g. alternative themes or states) and even animations, but it can be a little fiddly when doing it with developer tools when it’s only for testing reasons (i.e. the website doesn’t actually function that way for users). Similar to the other bookmarklets, use this one to rapidly toggle classes and save yourself time.
Create the following bookmarklet to target all elements that match your chosen “SELECTOR”, which, in turn, toggles the “CLASS.”
javascript: document.querySelectorAll("SELECTOR").forEach(element => element.classList.toggle("CLASS"));
Color widget bookmark
While not technically a “bookmarklet,” this bookmarkable data URI by Scott Jehl opens up an <input type="color">
in a new tab:
So hey here’s my new color picker app!
— Scott Jehl (@scottjehl) August 19, 2021
It’s um, just an HTML color input wrapped in a data URI so I can bookmark it. (Feel free to do so yourself):
data:text/html;charset=utf-8,%3Chtml%3E%3Ctitle%3EColor Picker%3C%2Ftitle%3E%3Cinput type%3D”color”%3E%3C%2Fhtml%3E pic.twitter.com/0QyFqAsUSq
data:text/html;charset=utf-8,%3Chtml%3E%3Ctitle%3EColor Picker%3C%2Ftitle%3E%3Cinput type%3D"color"%3E%3C%2Fhtml%3E
Why is that cool? Well, how many times have you needed to grab a color value off a page, only to find yourself cracking open DevTools, clicking through a bunch of elements, and pouring over CSS properties to find the value? Better to run this little guy, click the element, and get a color right away!
What other bookmarklets can you think of?
Are there any overly repetitive web development workflows that require you to use the web browser’s sometimes-awkward developer tools? If so, it’s super easy to create your own time-saving bookmarklets. Just remember to start the URL with javascript:
!
And if you’ve made a bookmarklet to simplify your workflow, I’d love to see it! Share them here in the comments and let’s get a nice collection going.
6 Useful Bookmarklets to Boost Web Development originally published on CSS-Tricks. You should get the newsletter.
from CSS-Tricks https://ift.tt/0lOqYzU
via IFTTT
Sunday, March 27, 2022
Partly Cloudy today!
With a high of F and a low of 38F. Currently, it's 44F and Clear outside.
Current wind speeds: 13 from the Southeast
Pollen: 0
Sunrise: March 27, 2022 at 06:43PM
Sunset: March 28, 2022 at 07:10AM
UV index: 0
Humidity: 54%
via https://ift.tt/gKFlNk4
March 28, 2022 at 10:05AM
Saturday, March 26, 2022
Partly Cloudy today!
With a high of F and a low of 32F. Currently, it's 51F and Clear outside.
Current wind speeds: 14 from the Southeast
Pollen: 0
Sunrise: March 26, 2022 at 06:45PM
Sunset: March 27, 2022 at 07:09AM
UV index: 0
Humidity: 51%
via https://ift.tt/wdpQnvr
March 27, 2022 at 10:05AM
Friday, March 25, 2022
Clear today!
With a high of F and a low of 37F. Currently, it's 39F and Clear outside.
Current wind speeds: 14 from the Southwest
Pollen: 0
Sunrise: March 25, 2022 at 06:46PM
Sunset: March 26, 2022 at 07:08AM
UV index: 0
Humidity: 67%
via https://ift.tt/ovANCWI
March 26, 2022 at 10:04AM
Thursday, March 24, 2022
Partly Cloudy today!
With a high of F and a low of 33F. Currently, it's 42F and Partly Cloudy outside.
Current wind speeds: 9 from the Northwest
Pollen: 0
Sunrise: March 24, 2022 at 06:48PM
Sunset: March 25, 2022 at 07:07AM
UV index: 0
Humidity: 53%
via https://ift.tt/gBbqOA1
March 25, 2022 at 10:03AM
Wednesday, March 23, 2022
Clear today!
With a high of F and a low of 26F. Currently, it's 32F and Clear outside.
Current wind speeds: 9 from the Northwest
Pollen: 0
Sunrise: March 23, 2022 at 06:49PM
Sunset: March 24, 2022 at 07:06AM
UV index: 0
Humidity: 46%
via https://ift.tt/gBbqOA1
March 24, 2022 at 10:05AM
Tuesday, March 22, 2022
Rain/Snow/Wind Early today!
With a high of F and a low of 26F. Currently, it's 31F and Partly Cloudy/Wind outside.
Current wind speeds: 20 from the Northwest
Pollen: 0
Sunrise: March 22, 2022 at 06:51PM
Sunset: March 23, 2022 at 07:05AM
UV index: 0
Humidity: 76%
via https://ift.tt/XQ18pym
March 23, 2022 at 10:03AM
Monday, March 21, 2022
Snow/Wind Early today!
With a high of F and a low of 24F. Currently, it's 29F and Snow outside.
Current wind speeds: 15 from the North
Pollen: 0
Sunrise: March 21, 2022 at 06:53PM
Sunset: March 22, 2022 at 07:04AM
UV index: 0
Humidity: 97%
via https://ift.tt/XQ18pym
March 22, 2022 at 10:05AM
Write HTML, the HTML Way (Not the XHTML Way)
You may not use XHTML (anymore), but when you write HTML, you may be more influenced by XHTML than you think. You are very likely writing HTML, the XHTML way.
What is the XHTML way of writing HTML, and what is the HTML way of writing HTML? Let’s have a look.
HTML, XHTML, HTML
In the 1990s, there was HTML. In the 2000s, there was XHTML. Then, in the 2010s, we switched back to HTML. That’s the simple story.
You can tell by the rough dates of the specifications, too: HTML “1” 1992, HTML 2.0 1995, HTML 3.2 1997, HTML 4.01 1999; XHTML 1.0 2000, XHTML 1.1 2001; “HTML5” 2007.
XHTML became popular when everyone believed XML and XML derivatives were the future. “XML all the things.” For HTML, this had a profound effect: The effect that we learned to write it the XHTML way.
The XHTML way of writing HTML
The XHTML way is well-documented, because XHTML 1.0 describes in great detail in its section on “Differences with HTML 4”:
- Documents must be well-formed.
- Element and attribute names must be in lower case.
- For non-empty elements, end tags are required.
- Attribute values must always be quoted.
- Attribute minimization is not supported.
- Empty elements need to be closed.
- White space handling in attribute values is done according to XML.
- Script and style elements need CDATA sections.
- SGML exclusions are not possible.
- The elements with
id
andname
attributes, likea
,applet
,form
,frame
,iframe
,img
, andmap
, should only useid
. - Attributes with pre-defined value sets are case-sensitive.
- Entity references as hex values must be in lowercase.
Does this look familiar? With the exception of marking CDATA content, as well as dealing with SGML exclusions, you probably follow all of these rules. All of them.
Although XHTML is dead, many of these rules have never been questioned again. Some have even been elevated to “best practices” for HTML.
That is the XHTML way of writing HTML, and its lasting impact on the field.
The HTML way of writing HTML
One way of walking us back is to negate the rules imposed by XHTML. Let’s actually do this (without the SGML part, because HTML isn’t based on SGML anymore):
- Documents may not be well-formed.
- Element and attribute names may not be in lower case.
- For non-empty elements, end tags are not always required.
- Attribute values may not always be quoted.
- Attribute minimization is supported.
- Empty elements don’t need to be closed.
- White space handling in attribute values isn’t done according to XML.
- Script and style elements don’t need CDATA sections.
- The elements with
id
andname
attributes may not only useid
. - Attributes with pre-defined value sets are not case-sensitive.
- Entity references as hex values may not only be in lowercase.
Let’s remove the esoteric things; the things that don’t seem relevant. This includes XML whitespace handling, CDATA sections, doubling of name
attribute values, the case of pre-defined value sets, and hexadecimal entity references:
- Documents may not be well-formed.
- Element and attribute names may not be in lowercase.
- For non-empty elements, end tags are not always required.
- Attribute values may not always be quoted.
- Attribute minimization is supported.
- Empty elements don’t need to be closed.
Peeling away from these rules, this looks a lot less like we’re working with XML, and more like working with HTML. But we’re not done yet.
“Documents may not be well-formed” suggests that it was fine if HTML code was invalid. It was fine for XHTML to point to wellformedness because of XML’s strict error handling. But while HTML documents work even when they contain severe syntax and wellformedness issues, it’s neither useful for the professional — nor our field — to use and abuse this resilience. (I’ve argued this case before in my article, “In Critical Defense of Frontend Development.”)
The HTML way would therefore not suggest “documents may not be well-formed.” It would also be clear that not only end, but also start tags aren’t always required. Rephrasing and reordering, this is the essence:
- Start and end tags are not always required.
- Empty elements don’t need to be closed.
- Element and attribute names may be lower or upper case.
- Attribute values may not always be quoted.
- Attribute minimization is supported.
Examples
How does this look like in practice? For start and end tags, be aware that many tags are optional. A paragraph and a list, for example, are written like this in XHTML:
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<ul>
<li>Praesent augue nisl</li>
<li>Lobortis nec bibendum ut</li>
<li>Dictum ac quam</li>
</ul>
In HTML, however, you can write them using only this code (which is valid):
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<ul>
<li>Praesent augue nisl
<li>Lobortis nec bibendum ut
<li>Dictum ac quam
</ul>
Developers also learned to write void elements, like so:
<br />
This is something XHTML brought to HTML, but as the slash has no effect on void elements, you only need this:
<br>
In HTML, you can also just write everything in all caps:
<A HREF="https://css-tricks.com/">CSS-Tricks</A>
It looks like you’re yelling and you may not like it, but it’s okay to write it like this.
When you want to condense that link, HTML offers you the option to leave out certain quotes:
<A HREF=https://css-tricks.com/>CSS-Tricks</A>
As a rule of thumb, when the attribute value doesn’t contain a space or an equal sign, it’s usually fine to drop the quotes.
Finally, HTML–HTML — not XHTML–HTML — also allows to minimize attributes. That is, instead of marking an input
element as required and read-only, like this:
<input type="text" required="required" readonly="readonly">
You can minimize the attributes:
<input type="text" required readonly>
If you’re not only taking advantage of the fact that the quotes aren’t needed, but that text
is the default for the type
attribute here (there are more such unneeded attribute–value combinations), you get an example that shows HTML in all its minimal beauty:
<input required readonly>
Write HTML, the HTML way
The above isn’t a representation of where HTML was in the 90s. HTML, back then, was loaded with <table>
elements for layout, packed with presentational code, largely invalid (as it’s still today), with wildly varying user agent support. Yet it’s the essence of what we would have wanted to keep if XML and XHTML hadn’t come around.
If you’re open to a suggestion of what a more comprehensive, contemporary way of writing HTML could look like, I have one. (HTML is my main focus area, so I’m augmenting this by links to some of my articles.)
- Respect syntax and semantics.
- Validate your HTML, and ship only valid HTML.
- Use the options HTML gives you, as long as you do so consistently.
- Remember that element and attribute names may be lowercase or uppercase.
- Keep use of HTML to the absolute minimum
- Remember that presentational and behavioral markup is to be handled by CSS and JavaScript instead.
- Remember that start and end tags are not always required.
- Remember that empty elements don’t need to be closed.
- Remember that some attributes have defaults that allow these attribute–value pairs to be omitted.
- Remember that attribute values may not always be quoted.
- Remember that attribute minimization is supported.
It’s not a coincidence that this resembles the three ground rules for HTML, that it works with the premise of a smaller payload also leading to faster sites, and that this follows the school of minimal web development. None of this is new — our field could merely decide to rediscover it. Tooling is available, too: html-minifier is probably the most established and able to handle all HTML optimizations.
You’ve learned HTML the XHTML way. HTML isn’t XHTML. Rediscover HTML, and help shape a new, modern way of writing HTML — which acknowledges, but isn’t necessarily based on XML.
Write HTML, the HTML Way (Not the XHTML Way) originally published on CSS-Tricks. You should get the newsletter.
from CSS-Tricks https://ift.tt/HFT02av
via IFTTT
Sunday, March 20, 2022
Mostly Cloudy/Wind today!
With a high of F and a low of 33F. Currently, it's 42F and Clear outside.
Current wind speeds: 10 from the South
Pollen: 0
Sunrise: March 20, 2022 at 06:54PM
Sunset: March 21, 2022 at 07:03AM
UV index: 0
Humidity: 46%
via https://ift.tt/oO83MwC
March 21, 2022 at 10:04AM
Saturday, March 19, 2022
Partly Cloudy today!
With a high of F and a low of 34F. Currently, it's 39F and Fair outside.
Current wind speeds: 11 from the South
Pollen: 0
Sunrise: March 19, 2022 at 06:56PM
Sunset: March 20, 2022 at 07:02AM
UV index: 0
Humidity: 50%
via https://ift.tt/mpaY1b8
March 20, 2022 at 10:04AM
Friday, March 18, 2022
Partly Cloudy today!
With a high of F and a low of 28F. Currently, it's 32F and Fair outside.
Current wind speeds: 9 from the Southwest
Pollen: 0
Sunrise: March 18, 2022 at 06:58PM
Sunset: March 19, 2022 at 07:01AM
UV index: 0
Humidity: 71%
via https://ift.tt/mpaY1b8
March 19, 2022 at 10:04AM
Optimizing SVG Patterns to Their Smallest Size
I recently created a brick wall pattern as part of my #PetitePatterns series, a challenge where I create organic-looking patterns or textures in SVG within 560 bytes (or approximately the size of two tweets). To fit this constraint, I have gone through a journey that has taught me some radical ways of optimizing SVG patterns so that they contain as little code as possible without affecting the overall image quality.
I want to walk you through the process and show you how we can take an SVG pattern that starts at 197 bytes all the way down to a mere 44 bytes — a whopping 77.7% reduction!
The SVG pattern
This is what’s called a “running bond” brick pattern. It’s the most common brick pattern out there, and one you’ve surely seen before: each row of bricks is offset by one half the length of a brick, creating a repeating staggered pattern. The arrangement is pretty simple, making SVG’s <pattern>
element a perfect fit to reproduce it in code.
The SVG <pattern>
element uses a pre-defined graphic object which can be replicated (or “tiled”) at fixed intervals along the horizontal and vertical axes. Essentially, we define a rectangular tile pattern and it gets repeated to paint the fill area.
First, let’s set the dimensions of a brick and the gap between each brick. For the sake of simplicity, let’s use clean, round numbers: a width of 100
and a height of 30
for the brick, and 10
for the horizontal and vertical gaps between them.
Next, we have to identify our “base” tile. And by “tile” I’m talking about pattern tiles rather than physical tiles, not to be confused with the bricks. Let’s use the highlighted part of the image above as our pattern tile: two whole bricks in the first row, and one whole sandwiched between two half bricks in the second row. Notice how and where the gaps are included, because those need to be included in the repeated pattern tile.
When using <pattern>
, we have to define the pattern’s width
and height
, which correspond to the width and height of the base tile. To get the dimensions, we need a little math:
Tile Width = 2(Brick Width) + 2(Gap) = 2(100) + 2(10) = 220
Tile Height = 2(Bright Height) + 2(Gap) = 2(30) + 2(10) = 80
Alright, so our pattern tile is 220✕80
. We also have to set the patternUnits
attribute, where the value userSpaceOnUse
essentially means pixels. Finally, adding an id
to the pattern is necessary so that it can be referenced when we are painting another element with it.
<pattern id="p" width="220" height="80" patternUnits="userSpaceOnUse">
<!-- pattern content here -->
</pattern>
Now that we have established the tile dimensions, the challenge is to create the code for the tile in a way that renders the graphic with the smallest number of bytes possible. This is what we hope to end up with at the very end:
Initial markup (197 bytes)
The simplest and most declarative approach to recreate this pattern that comes to my mind is to draw five rectangles. By default, the fill
of an SVG element is black and the stroke
is transparent. This works well for optimizing SVG patterns, as we don’t have to explicitly declare those in the code.
Each line in the code below defines a rectangle. The width
and height
are always set, and the x
and y
positions are only set if a rectangle is offset from the 0
position.
<rect width="100" height="30"/>
<rect x="110" width="100" height="30"/>
<rect y="40" width="45" height="30"/>
<rect x="55" y="40" width="100" height="30"/>
<rect x="165" y="40" width="55" height="30"/>
The top row of the tile contained two full-width bricks, the second brick is positioned to x="110"
allowing 10
pixels of gap before the brick. Similarly there’s 10
pixels of gap after, because the brick ends at 210
pixels (110 + 100 = 210
) on the horizontal axis even though the <pattern>
width is 220
pixels. We need that little bit of extra space; otherwise the second brick would merge with the first brick in the adjacent tile.
The bricks in the second (bottom) row are offset so the row contains two half bricks and one whole brick. In this case, we want the half-width bricks to merge so there’s no gap at the start or the end, allowing them to seamlessly flow with the bricks in adjoining pattern tiles. When offsetting these bricks, we also have to include half gaps, thus the x
values are 55
and 165
, respectively.
Element reuse, (-43B, 154B total)
It seems inefficient to define each brick so explicitly. Isn’t there some way to optimize SVG patterns by reusing the shapes instead?
I don’t think it’s widely known that SVG has a <use>
element. You can reference another element with it and render that referenced element wherever <use>
is used. This saves quite a few bytes because we can omit specifying the widths and heights of each brick, except for the first one.
That said, <use>
does come with a little price. That is, we have to add an id
for the element we want to reuse.
<rect id="b" width="100" height="30"/>
<use href="#b" x="110"/>
<use href="#b" x="-55" y="40"/>
<use href="#b" x="55" y="40"/>
<use href="#b" x="165" y="40"/>
The shortest id
possible is one character, so I chose “b” for brick. The <use>
element can be positioned similarly to <rect>
, with the x
and y
attributes as offsets. Since each brick is full-width now that we’ve switched to <use>
(remember, we explicitly halved the bricks in the second row of the pattern tile), we have to use a negative x
value in the second row, then make sure the last brick overflows from the tile for that seamless connection between bricks. These are okay, though, because anything that falls outside of the pattern tile is automatically cut off.
Can you spot some repeating strings that can be written more efficiently? Let’s work on those next.
Rewriting to path (-54B, 100B total)
<path>
is probably the most powerful element in SVG. You can draw just about any shape with “commands” in its d
attribute. There are 20 commands available, but we only need the simplest ones for rectangles.
Here’s where I landed with that:
<path d="M0 0h100v30h-100z
M110 0h100v30h-100
M0 40h45v30h-45z
M55 40h100v30h-100z
M165 40h55v30h-55z"/>
I know, super weird numbers and letters! They all have meaning, of course. Here’s what’s happening in this specific case:
M{x} {y}
: Moves to a point based on coordinates.z
: Closes the current segment.h{x}
: Draws a horizontal line from the current point, with the length ofx
in the direction defined by the sign ofx
. Lowercasex
indicates a relative coordinate.v{y}
: Draws a vertical line from the current point, with the length ofy
in the direction defined by the sign ofy
. Lowercasey
indicates a relative coordinate.
This markup is much more terse than the previous one (line breaks and indentation whitespace is only for readability). And, hey, we’ve managed to cut out half of the initial size, arriving at 100 bytes. Still, something makes me feel like this could be smaller…
Tile revision (-38B, 62B total)
Doesn’t our pattern tile have repeating parts? It’s clear that in the first row a whole brick is repeated, but what about the second row? It’s a bit harder to see, but if we cut the middle brick in half it becomes obvious.
Well, the middle brick isn’t exactly cut in half. There’s a slight offset because we also have to account for the gap. Anyways, we just found a simpler base tile pattern, which means fewer bytes! This also means we have to halve the width
of our <pattern>
element from 220 to 110.
<pattern id="p" width="110" height="80" patternUnits="userSpaceOnUse">
<!-- pattern content here -->
</pattern>
Now let’s see how the simplified tile is drawn with <path>
:
<path d="M0 0h100v30h-100z
M0 40h45v30h-45z
M55 40h55v30h-55z"/>
The size is reduced to 62 bytes, which is already less than a third of the original size! But why stop here when there’s even more we can do!
Shortening path commands (-9B, 53B total)
It’s worth getting a little deeper into the <path>
element because it provides more hints for optimizing SVG patterns. One misconception I’ve had when working with <path>
is regarding how the fill
attribute works. Having played a lot with MS Paint in my childhood, I’ve learned that any shape I want to fill with a solid color has to be closed, i.e. have no open points. Otherwise, the paint will leak out of the shape and spill over everything.
In SVG, however, this is not true. Let me quote the spec itself:
The fill operation fills open subpaths by performing the fill operation as if an additional “closepath” command were added to the path to connect the last point of the subpath with the first point of the subpath.
This means we can omit the close path commands (z
), because the subpaths are considered automatically closed when filled.
Another useful thing to know about path commands is that they come in uppercase and lowercase variations. Lowercase letters mean that relative coordinates are used; uppercase letters mean absolute coordinates are used instead.
It’s a little trickier than that with the H
and V
commands because they only include one coordinate. Here’s how I would describe these two commands:
H{x}
: Draws a horizontal line from the current point to coordinatex
.V{y}
: Draws a vertical line from the current point to coordinatey
.
When we are drawing the first brick in the pattern tile, we start from the (0,0)
coordinates. We then draw a horizontal line to (100,0)
and a vertical line to (100,30)
, and finally, draw a horizontal line to (0,30)
. We used the h-100
command in the last line, but it is the equivalent of H0
, which is two bytes instead of five. We can replace two similar occurrences and pare the code of our <path>
down to this:
<path d="M0 0h100v30H0
M0 40h45v30H0
M55 40h55v30H55"/>
Another 9 bytes shaved off — how much smaller can we go?
Bridging (-5B, 48B total)
The longest commands standing in our way of a fully-optimized SVG pattern are the “move to” commands which take up 4, 5, and 6 bytes, respectively. One constraint we have is that:
A path data segment (if there is one) must begin with a “moveto” command.
But that’s okay. The first one is the shortest anyways. If we swap the rows, we can come up with a path definition where we only have to move either horizontally or vertically between the bricks. What if we could use the h
and v
commands there instead of M
?
The above diagram shows how the three shapes can be drawn with a single path. Note that we are leveraging the fact that the fill
operation automatically closes the open part between (110,0)
and (0,0)
. With this rearrangement, we also moved the gap to the left of the full-width brick in the second row. Here’s how the code looks, still broken into one brick per line:
<path d="M0 0v30h50V0
h10v30h50
v10H10v30h100V0"/>
Surely, we’ve found the absolute smallest solution now that we’re down to 48 bytes, right?! Well…
Digit trimming (-4B, 44B total)
If you can be a bit flexible with the dimensions, there’s another little way we can optimize SVG patterns. We’ve been working with a brick width of 100
pixels, but that’s three bytes. Changing it to 90
means one less byte whenever we need to write it. Similarly, we used a gap of 10
pixels — but if we change it to 8
instead, we save a byte on each of those occurrences.
<path d="M0 0v30h45V0
h8v30h45
v8H8v30h90V0"/>
Of course, this also means we have to adjust the pattern dimensions accordingly. Here’s the final optimized SVG pattern code:
<pattern id="p" width="98" height="76" patternUnits="userSpaceOnUse">
<path d="M0 0v30h45V0h8v30h45v8H8v30h90V0"/>
</pattern>
The second line in the above snippet — not counting the indentations — is 44 bytes. We got here from 197 bytes in six iterations. That’s a chunky 77.7% size reduction!
I’m wondering though… is this really the smallest size possible? Have we looked at all possible ways to optimize SVG patterns?
I invite you to try and further minify this code, or even experiment with alternative methods for optimizing SVG patterns. I would love to see if we could find the true global minimum with the wisdom of the crowd!
More on creating and optimizing SVG patterns
If you are interested to learn more about creating and optimizing SVG patterns, read my article about creating patterns with SVG filters. Or, if you want to check out a gallery of 60+ patterns, you can view the PetitePatterns CodePen Collection. Lastly, you’re welcome to watch my tutorials on YouTube to help you get even deeper into SVG patterns.
Optimizing SVG Patterns to Their Smallest Size originally published on CSS-Tricks. You should get the newsletter.
from CSS-Tricks https://ift.tt/gtrYjby
via IFTTT
Thursday, March 17, 2022
Mostly Clear today!
With a high of F and a low of 21F. Currently, it's 30F and Partly Cloudy outside.
Current wind speeds: 10 from the Northwest
Pollen: 0
Sunrise: March 17, 2022 at 06:59PM
Sunset: March 18, 2022 at 07:00AM
UV index: 0
Humidity: 96%
via https://ift.tt/v6jaHos
March 18, 2022 at 10:04AM
Wednesday, March 16, 2022
Rain/Snow/Wind today!
With a high of F and a low of 28F. Currently, it's 45F and Cloudy outside.
Current wind speeds: 5 from the Northeast
Pollen: 0
Sunrise: March 16, 2022 at 07:01PM
Sunset: March 17, 2022 at 06:59AM
UV index: 0
Humidity: 55%
via https://ift.tt/kV3pz6D
March 17, 2022 at 10:03AM
Tuesday, March 15, 2022
Clear today!
With a high of F and a low of 32F. Currently, it's 45F and Clear outside.
Current wind speeds: 8 from the Southwest
Pollen: 0
Sunrise: March 15, 2022 at 07:02PM
Sunset: March 16, 2022 at 06:58AM
UV index: 0
Humidity: 30%
via https://ift.tt/kV3pz6D
March 16, 2022 at 10:04AM
CSS-Tricks is joining DigitalOcean!
Hey hey!
I’ve got a big announcement to make here. (Where’s my gong? I feel like this really needs a good gong hit.)
CSS-Tricks, this very website you’re looking at, has been acquired by DigitalOcean!
You can hear from them directly on the DigitalOcean blog as well.
This will be the most fun if we have a conversation about it, so allow me to kick it off. I’ll pretend to be you at first and then you can be you in the comments.
Hey, congrats!
Thanks!
DigitalOcean? Aren’t they like a… web host?
They are! A very good one. You can build anything on DigitalOcean infrastructure (probably best to think of them as a cloud computing platform that has tools ranging from servers to managed Kubernetes). One thing I think is particularly cool is their new App Platform which to me feels extra aligned with front-end developers like me. We’ve covered that before. Also, their whole concept of Droplets (super simple servers that are quick to spin up) has been transformative in the industry. But more importantly about this acquisition… have you seen their DigitalOcean Community site? It’s loaded with top-notch developer education. DigitalOcean has been super committed to that for a long time, and to me makes this a very natural and well-suited move.
What happens to CSS-Tricks?
The site and content is staying right here. DigitalOcean is committed to continuing to produce high-quality content on front-end development and tending to the trove of content that exists here already.
Will you still be running CSS-Tricks?
I will be working with the DigitalOcean team as an advisor as we transition CSS-Tricks to DigitalOcean’s management, and will then step back to focus on my other projects.
Why now?
When I started CSS-Tricks in 2007, I couldn’t have imagined how much it would grow. I wanted it to grow, that was the plan, but now it’s a far bigger job than any one person can do. That, I was never ready for.
Let me take a quick moment to give some thanks here. I had the incredible help of Geoff as lead editor, sponsor wrangler, and site manager. Robin turned the newsletter into the must-read industry rag it is now. It’s a family business as well! My wife Miranda helped with the books, working with authors, and her guidance on running the site as a proper publication has led the site where it is. I literally couldn’t have done it without any one of them. And of course, the incredible group of authors, with a special shout out to Sarah, a long-time staff writer and friend.
A small but mighty team, indeed. And that’s the thing. CSS-Tricks deserves more human muscle behind it than I’ve been able to provide for it. That’s where DigitalOcean comes in. That’s the “why now.” They have the resources to put behind CSS-Tricks, and the motivation to do so. I fully trust them to do it, as they’ve been successfully doing it themselves for a long time.
OK! Your turn! If you have any thoughts or questions, feel free to comment below. We’ll read them all and publish anything useful and constructive.
CSS-Tricks is joining DigitalOcean! originally published on CSS-Tricks. You should get the newsletter.
from CSS-Tricks https://ift.tt/W6Z21A3
via IFTTT
Mostly Clear today!
With a high of F and a low of 15F. Currently, it's 14F and Clear outside. Current wind speeds: 13 from the Southwest Pollen: 0 S...
-
So you want an auto-playing looping video without sound? In popular vernacular this is the very meaning of the word GIF . The word has stuck...
-
With a high of F and a low of 31F. Currently, it's 37F and Cloudy outside. Current wind speeds: 7 from the Northeast Pollen: 0 S...
-
Last year , we kicked out a roundup of published surveys, research, and other findings from around the web. There were some nice nuggets in ...