Your CSS reset needs text-size-adjust (probably)

Kilian Valkhof:

[…] Mobile Safari increases the default font-size when you switch a website from portrait to landscape. On phones that is, it doesn’t do it on iPad. Safari has been doing this for a long time, as a way to improve readability on non-mobile optimized websites. While undoubtedly useful in a time when literally no website was optimized for mobile, it’s significantly less helpful nowadays. […] Text size increasing randomly in a single situation is exactly the type of thing you want to guard for with a CSS reset.

This is very literally what text-size-adjust does. MDN:

When an element containing text uses 100% of the screen’s width, the algorithm increases its text size, but without modifying the layout. The text-size-adjust property allows web authors to disable or modify this behavior, as web pages designed with small screens in mind do not need it.

You can see Apple’s own docs showing off this is exactly what they do (on iPhones). There is an ancient bug where this would prevent zooming, but probably not a huge concern anymore.

Kilian’s recommendation:

html {
  -moz-text-size-adjust: none;
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
}

Firefox doesn’t even support it, so I’d maybe lose that vendor prefix, but otherwise I’d say I’m on board. I’d like to think I can handle my own text sizing.

Reminds me of how Mobile Safari does that zooming thing with text inputs under 16px, so watch out for that too.

To Shared LinkPermalink on CSS-Tricks


Your CSS reset needs text-size-adjust (probably) originally published on CSS-Tricks. You should get the newsletter.

The text-shadow CSS Property

This article was originally posted at https://medium.com/@christinatruong/the-text-shadow-css-property-d1064bb1b27d and was kindly shared by Christina Truong. Check out more of her work at https://christinatruong.com.

When adding CSS styles to text on an HTML page, it’s usually best to keep it subtle, to make sure that the content on your page is easy to read. But sometimes you may want to make a small block of text stand out a little more than the rest. In this post, I’ll go over how to use the text-shadow CSS property to add a drop shadow to your text.

UNLIMITED DOWNLOADS: 500,000+ WordPress & Design Assets

Sign up for Envato Elements and get unlimited downloads starting at only $16.50 per month!



 

Prefer to watch a video? This article is a companion piece to my Decoded by Christina series on YouTube.

There are some basic ways to make your text stand out. You can make it bold, change the color, or use different font-sizes.

Another option is to use the text-shadow property to add a drop shadow. There are four values used with this property. Two are required, the offset-x and offset-y, and two are optional, the blur-radius and color value.

/* offset-x | offset-y | blur-radius | color */
text-shadow: 2px 2px 4px green;

Let’s go over how to define each value.

offset-x and offset-y

The offset-x value determines how far away, from the element, the shadow will appear on the x-axis, which runs left to right. The second value, the offset-y, determines the distance of the shadow on the y-axis, which runs top to bottom.

text-shadow

These values can be defined with any length data type, which is a number followed by any unit used to represent a distance value (e.g. px, em, rem or a percentage). Also, when using a property with multiple values, each has to be separated by a space.

/* offset-x | offset-y */
text-shadow: 2px 2px;

Since both the offset-x and offset-y values are required, if you add only value, you won’t see any change. But if you only want a shadow on the x-axis, then set the offset-y value to 0 or vice versa.

text-shadow: 2px 0px; /* will only show the shadow on the x-axis */
text-shadow: 0px 2px; /* will only show the shadow on the y-axis */

I used to always get the direction of the x- and y-axis mixed up until I saw an example using Beyoncé’s “Irreplaceable” lyrics as a reminder. In the song, she sings to her ex, “to the left to the left, everything you own in the box to the left.” So, ex (or x) to the left!

blur-radius and color

If you only define the offset-x and offset-y values, the shadow will look exactly like a copy of the text.

To create a softer shadow effect, add a third value, the blur-radius. This will blur the edges of the shadow. Any length data type can be used here as well. The larger the value, the bigger and more transparent the blur effect.

The last value is used to change the shadow from the default black colour to any other colour by adding a color value (e.g. keyword, hex code).

CSS text-shadow

Putting it all together

Most of the time, text-shadow effects are used add a subtle drop shadow and not quite like the example below. But for demonstration and testing, using values that create a more prominent style will make it easier to see what each value does.

See the Pen
text-shadow example
by Christina Truong (@christinatruong)
on CodePen.light

To make a text-shadow effect a little more subtle, I generally use a dark gray color or something that matches to the background colour, rather than pure black. This will create a softer shadow. (Note that the hex values in the example is using the shorthand notation.)

For the other values, I find that 1–3px is usually enough to give you just a bit of a shadow effect without overwhelming the text. Though there are always exceptions to the rule so I would suggest playing around with different values to get the effect you’re looking for. But in a nutshell, this is how you add a drop shadow to your text.

And that’s it!

 

Drawing Text on Images With Pillow and Python

Pillow supports drawing text on your images in addition to shapes. Pillow uses its own font file format to store bitmap fonts, limited to 256 characters. Pillow also supports TrueType and OpenType fonts as well as other font formats supported by the FreeType library.

In this chapter, you will learn about the following:

Making Stagger Reveal Animations for Text

Thibaud Allie made this wonderful animation which you can see live on the site of Dani Morales. It happens when you click on “About” (and then “Close”). This kind of show/hide animation on the typographic elements is being used in many designs lately. At Codrops we call it a “reveal” animation.

I fell in love with that lettering effect and wanted to reimplement it using GSAP and Splitting.js. So I made a similar typography based layout and move the lines of text by staggering the letter animations.

The simplified markup looks like this:

<section class="content__item content__item--home content__item--current">
	<p class="content__paragraph" data-splitting>Something</p>
	<p class="content__paragraph" data-splitting>More</p>
	...
</section>
<section class="content__item content__item--about">
	<p class="content__paragraph" data-splitting>Something</p>
	<p class="content__paragraph" data-splitting>Else</p>
	...
</section>

Note that the necessary style for the content__paragraph element is overflow: hidden so that the reveal/unreveal animation works.

All elements with the “data-splitting” attribute will be split up into spans that we can then animate individually. So let’s have a look at the JavaScript for that.

Initially, we need to import some libraries and styles:

import "splitting/dist/splitting.css";
import "splitting/dist/splitting-cells.css";
import Splitting from "splitting";
import { gsap } from 'gsap';
import { preloadFonts } from './utils';
import Cursor from "./cursor";

I’m using some Adobe Fonts here (Freight Big Pro and Tenon) so let’s preload them:

preloadFonts('lwc3axy').then(() => document.body.classList.remove('loading'));

Then it’s time to split all the texts into spans:

Splitting();

The design has a custom cursor that we call as follows:

new Cursor(document.querySelector('.cursor'))

Let’s get all relevant DOM elements:

let DOM = {
    content: {
        home: {
            section: document.querySelector('.content__item--home'),
            get chars() {
                return this.section.querySelectorAll('.content__paragraph .word > .char, .whitespace');
            },
            isVisible: true
        },
        about: {
            section: document.querySelector('.content__item--about'),
            get chars() {
                return this.section.querySelectorAll('.content__paragraph .word > .char, .whitespace')
            },
            get picture() {
                return this.section.querySelector('.content__figure');
            },
            isVisible: false
        }
    },
    links: {
        about: {
            anchor: document.querySelector('a.frame__about'),
            get stateElement() {
                return this.anchor.children;
            }
        },
        home: document.querySelector('a.frame__home')
    }
};

Let’s have a look at the GSAP timeline now where all the magic happens (and also some default settings):

const timelineSettings = {
    staggerValue: 0.014,
    charsDuration: 0.5
};
const timeline = gsap.timeline({paused: true})
    .addLabel('start')
    // Stagger the animation of the home section chars
    .staggerTo( DOM.content.home.chars, timelineSettings.charsDuration, {
        ease: 'Power3.easeIn',
        y: '-100%',
        opacity: 0
    }, timelineSettings.staggerValue, 'start')
    // Here we do the switch
    // We need to toggle the current class for the content sections
    .addLabel('switchtime')
    .add( () => {
        DOM.content.home.section.classList.toggle('content__item--current');
        DOM.content.about.section.classList.toggle('content__item--current');
    })
    // Change the body's background color
    .to(document.body, {
        duration: 0.8,
        ease: 'Power1.easeInOut',
        backgroundColor: '#c3b996'
    }, 'switchtime-=timelineSettings.charsDuration/4')
    // Start values for the about section elements that will animate in
    .set(DOM.content.about.chars, {
        y: '100%'
    }, 'switchtime')
    .set(DOM.content.about.picture, {
        y: '40%',
        rotation: -4,
        opacity: 0
    }, 'switchtime')
    // Stagger the animation of the about section chars
    .staggerTo( DOM.content.about.chars, timelineSettings.charsDuration, {
        ease: 'Power3.easeOut',
        y: '0%'
    }, timelineSettings.staggerValue, 'switchtime')
    // Finally, animate the picture in
    .to( DOM.content.about.picture, 0.8, {
        ease: 'Power3.easeOut',
        y: '0%',
        opacity: 1,
        rotation: 0
    }, 'switchtime+=0.6');

When we click on the “About” or logo/home link we want to toggle the current content by playing and reversing the timeline. We also want to toggle the current state of the “About” and “Close” link:

const switchContent = () => {
    DOM.links.about.stateElement[0].classList[DOM.content.about.isVisible ? 'add' : 'remove']('frame__about-item--current');
    DOM.links.about.stateElement[1].classList[DOM.content.about.isVisible ? 'remove' : 'add']('frame__about-item--current');
    timeline[DOM.content.about.isVisible ? 'reverse' : 'play']();
    DOM.content.about.isVisible = !DOM.content.about.isVisible;
    DOM.content.home.isVisible = !DOM.content.about.isVisible;
};

DOM.links.about.anchor.addEventListener('click', () => switchContent());
DOM.links.home.addEventListener('click', () => {
    if ( DOM.content.home.isVisible ) return;
    switchContent();
});

And that’s all the magic! It’s not too complicated and you can do many nice effects with this kind of letter animation.

Thank you for reading and hopefully this was relevant and helpful 🙂

Please reach out to me @codrops or @crnacura if you have any questions or suggestions.

Credits

The post Making Stagger Reveal Animations for Text appeared first on Codrops.

The Contrast Triangle

Chip Cullen:

Let’s say you’re building a site, and you’re working with a designer. They come to you with some solid designs, and you’re ready to go. You’re also a conscientious front end developer and you like to make sure the sites you build are accessible. The designs you’re working from have some body copy, but you notice that the links inside the body copy are missing underlines.

You are now in The Contrast Triangle.

The “triangle” meaning a three-sided comparison:

  • The contrast between the background and text
  • The contrast between the background and links
  • the contrast between text and links

I would think this matters whether you underline links or not, but I take the point that without underlines the problem is worse.

I’d also argue the problem is even more complicated. You’ve also got to consider the text when it is selected, and make sure everything has contrast when that is the case too. And the hover states, active states, visited states, and focus states. So it’s really like hexacontakaienneagon of contrast or something.

Direct Link to ArticlePermalink

The post The Contrast Triangle appeared first on CSS-Tricks.

ANTLR: An Informal Introduction

In this article, I am going to introduce you to ANTLR's powerful framework. Equipped with this framework, we will also write a relatively simple language that coordinates the process of shearing a metal sheet (or any other sheet). The first steps in the language are going to be relatively simple, but in the next articles, more and more details will emerge. In the end, we will have something fully-fledged and effectively functioning. So, without further ado, let's take a closer look at how ANTLR works. 

What Is ANTLR? And How Can You Use It?

ANTLR (ANother Tool for Language Recognition), according to Terence Parr, "is a powerful parser generator for reading, processing, executing, or translating structured text or binary files. It’s widely used to build languages, tools, and frameworks. From grammar, ANTLR generates a parser that can build and walk parse trees."

SVG Filter Effects: Conforming Text to Surface Texture with <feDisplacementMap>

SVGFilterEffects_displacementMap_featured

Applying texture to text is one of the most popular text effects in graphic design. As much of print and graphic design has made its way into the Web platform, such effects have also been recreated on the Web using CSS, as well as using features of SVG such as patterns, masks and clipping paths. I have an article right here on Codrops that gives you a full overview of different ways to create textured text on the Web using CSS and SVG today that you may be interested in checking out. Yoksel touched on another area of this topic and wrote an article all about animating text fills.

However, one effect that was untouched on was that of text conforming to the texture of a surface. When text conforms to a surface, it takes the shape of that surface. Depending on the surface and texture used, you could end up some really eye-catching results. This is what this article will touch on. And the best part? All these effects are applied to real, searchable, selectable and accessible text.

This is the fifth in a series of articles on SVG filters. In the previous weeks, we got an introduction to SVG filters and learned how to create and use them to produce various effects from outlined text to posterized images, and how to replicate Photoshop-like duotone image effects with SVG filter operations.

Conforming Text to Surface Texture: The Photoshop Way

As with the duotone effect, I looked into how to make text conform to surface texture in Photoshop in an attempt to replicate that effect with SVG filters. I found this step-by-step tutorial on YouTube. The following video is a sped-up version of that tutorial:

In the Photoshop tutorial, the designer created this effect by using what is known as a displacement map. A displacement map is an image whose color information is used to distort the content of another element. To create our text effect, the texture of the image will be used to distort the text so that it conforms to the shape of the texture.

In Photoshop, in order to conform text to a surface the designer followed these steps:

  1. Desaturate the image.
  2. Reduce the amount of detail in the image by blurring it by 1px.
  3. Save the image as a displacement map.
  4. Create the text, and apply a distortion filter to it using the image as a displacement map.
  5. Re-use the original image as a background behind the text.
  6. Then refine the effect more by adding a slight transparency to the text and blending it with the background image.

The displacement map image is blurred in the second step before it is used to displace the text because if the image has too much or too little detail the resulting effect would look less realistic. Usually blurring the image up to 2px is enough to get a moderate amount of detail that’s just enough.

If you’ve read the previous articles in this series, you know that thinking in steps is important to create and recreate effects with SVG filter primitives. And you may have already guessed how to replicate some of these steps using SVG filter primitives, a few of which we have covered in the previous articles.

But the most important step in this effect is the creation and application of the displacement map. How do we do that in SVG?

Conforming Text to Surface Texture in SVG

In order to recreate the effect from the Photoshop tutorial above, we need to first create a displacement map. In SVG, the feDisplacementMap primitive is used to displace content using a displacement map.

feDisplacementMap takes two inputs to produce one result. The image you want to use to displace your content is specified in the in2 attribute. The in attribute is reserved for the input that you want to apply the displacement effect to.

And as with all other primitives, the input for feDisplacementMap can be anything from the SourceGraphic itself to the result of another filter operation. And since we want to apply the displacement map to our source text, this means that the in attribute will have SourceGraphic for a value.

So let’s recreate the Photoshop tutorial steps with SVG filter primitives. The process of conforming text to texture in SVG is very similar to that we saw in Photoshop. I’ll elaborate on each step as we go.

  1. Get the image that will be used as a texture using feImage.
  2. Desaturate the image using feColorMatrix.
  3. Apply a 0.5px Gaussian blur to the image using feGaussianBlur.
  4. Use the image to distort the text using feDisplacementMap.
  5. Blend the text into the background image using feBlend and apply a translucent effect to it (decrease opacity using feComponentTransfer).
  6. Display the text and the image behind it by merging the two layers using feMerge.

The feImage filter primitive is the filter version of the <image> element and has the same attributes as the <image> element too. So in order to render an image in the filter region, we will use feImage. Once we’ve got our image, we can use it as input to other filter operations. It will be used by the feColorMatrix operation to boot because we need to desaturate it.

We’ve mentioned feColorMatrix before, but what we didn’t mention is it comes with a few keywords that are shortcuts to pre-defined matrices. Instead of always having to provide a matrix as a value, you can change the type attribute and use one of the keywords available:

matrix | saturate | hueRotate | luminanceToAlpha

The matrix type is what you’d use when you want to provide a custom matrix as a value for the matrix operation. The other keywords are convenience shortcuts.

To desaturate an image, we use the saturate type. You specify the amount by which you want to desaturate the image in the values attribute. Since we want to completely desaturate our image, we will provide 0 as a value. Note that values are provided as fractions, with 1 (default value) being fully saturated and 0 being completely desaturated (grayscale).

So, let’s start translating our steps into code:

<!-- I'm extending the filter region just to increase its area for visual purposes. This is not required or needed for the effect to work.-->
<filter id="conform" x="-50%" y="-50%" width="200%" height="200%"> 
        
        <!-- Get the image. -->
        <feImage xlink:href="..." x="0" y="0" width="100%" height="100%" preserveAspectRatio="none"></feImage>
        
        <!-- Desaturate the image. -->
        <feColorMatrix type="saturate" values="0" result="IMAGE"/>

        <!-- ... -->

At this point, our filter region looks like this:

Screen Shot 2019-01-16 at 15.15.00

After desaturating the image, we will blur it by a small amount enough to reduce the amount of detail without losing too much of it. For this particular effect, I chose to blur it by 0.25 pixels only. You may need to experiment with the values to get the right one depending on the image you use and the effect you’re after.

<!-- I'm extending the filter region just to increase its area for visual purposes. This is not required or needed for the effect to work.-->
<filter id="conform" x="-50%" y="-50%" width="200%" height="200%"> 
        
        <!-- Get the image. -->
        <feImage xlink:href="..." x="0" y="0" width="100%" height="100%" preserveAspectRatio="none"></feImage>
        
        <!-- Desaturate the image. -->
        <feColorMatrix type="saturate" values="0" result="IMAGE"/>

        <!-- decrease level of details so the effect on text is more realistic -->
        <feGaussianBlur in="IMAGE" stdDeviation="0.25" result="MAP"></feGaussianBlur>

        <!-- ... -->

And our displacement map now looks like this:

Screen Shot 2019-01-16 at 15.43.19

Using feDisplacementMap we can now distort the text with our displacement map:

<!-- I'm extending the filter region just to increase its area for visual purposes. This is not required or needed for the effect to work.-->
<filter id="conform" x="-50%" y="-50%" width="200%" height="200%"> 
        
        <!-- Get the image. -->
        <feImage xlink:href="..." x="0" y="0" width="100%" height="100%" preserveAspectRatio="none"></feImage>
        
        <!-- Desaturate the image. -->
        <feColorMatrix type="saturate" values="0" result="IMAGE"/>

        <!-- decrease level of details so the effect on text is more realistic -->
        <feGaussianBlur in="IMAGE" stdDeviation="0.25" result="MAP"></feGaussianBlur>
        
        <!-- Use the displacement map to distort the source text -->
        <feDisplacementMap in="SourceGraphic" in2="MAP" scale="15" xChannelSelector="R" yChannelSelector="R" result="TEXTURED_TEXT"></feDisplacementMap>

        <!-- ... -->

At this point, the image we used to distort the text is no longer rendered as it has been used to generate a new result, which is the distorted text. The filter region at this point thus only contains the text that is now conforming to the shape and texture of the fabric in our displacement map:

Screen Shot 2019-01-16 at 15.39.23

You can already see the texture of the fabric take shape on the edges of the text. This is great.

Just like in the Photoshop tutorial, we will now re-display the image behind the text. We will do that by using feImage again:

<!-- I'm extending the filter region just to increase its area for visual purposes. This is not required or needed for the effect to work.-->
<filter id="conform" x="-50%" y="-50%" width="200%" height="200%"> 
        
        <!-- Get the image. -->
        <feImage xlink:href="..." x="0" y="0" width="100%" height="100%" preserveAspectRatio="none"></feImage>
        
        <!-- Desaturate the image. -->
        <feColorMatrix type="saturate" values="0" result="IMAGE"/>

        <!-- decrease level of details so the effect on text is more realistic -->
        <feGaussianBlur in="IMAGE" stdDeviation="0.25" result="MAP"></feGaussianBlur>
        
        <!-- Use the displacement map to distort the source text -->
        <feDisplacementMap in="SourceGraphic" in2="MAP" scale="15" xChannelSelector="R" yChannelSelector="R" result="TEXTURED_TEXT"></feDisplacementMap>
        
        <!-- Re-display the image as a background image -->
        <feImage xlink:href="..." x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" result="BG"></feImage>
        
        <!-- ... -->

Lastly, we want to blend the text into the background image to improve the effect. We will decrease the opacity of the text to 0.9 using feColorMatrix, and then we will use the feBlend primitive to apply a blending mode to the text.

Similar to CSS Blend Modes, we have 16 blend modes to choose from. For our effect, the multiply blend mode will do. (In the Photoshop tutorial, the designer used the linear burn, which is not available in SVG/CSS.)

feBlend will take two inputs to blend together: the text and the background image:

<!-- I'm extending the filter region just to increase its area for visual purposes. This is not required or needed for the effect to work.-->
<filter id="conform" x="-50%" y="-50%" width="200%" height="200%"> 
        
        <!-- Get the image. -->
        <feImage xlink:href="..." x="0" y="0" width="100%" height="100%" preserveAspectRatio="none"></feImage>
        
        <!-- Desaturate the image. -->
        <feColorMatrix type="saturate" values="0" result="IMAGE"/>

        
        <feGaussianBlur in="IMAGE" stdDeviation="0.25" result="MAP"></feGaussianBlur>
        
        <!-- Use the displacement map to distort the source text -->
        <feDisplacementMap in="SourceGraphic" in2="MAP" scale="15" xChannelSelector="R" yChannelSelector="R" result="TEXTURED_TEXT"></feDisplacementMap>
        
        <!---->
        <feImage xlink:href="..." x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" result="BG"></feImage>
        
        <!-- Reduce the opacity of the text -->
        <feColorMatrix in="Textured_Text" result="Textured_Text_2" type="matrix" 
           values="1 0 0 0 0 
                   0 1 0 0 0 
                   0 0 1 0 0 
                   0 0 0 .9 0" />      

        <!-- Blend the text with the background -->
        <feBlend in="BG" in2="Textured_Text_2" mode="multiply" result="BLENDED_TEXT"></feBlend>

        <!-- ... -->

And last by not least, we will layer the new blended text layer on top of the background image layer with feMerge:

<!-- I'm extending the filter region just to increase its area for visual purposes. This is not required or needed for the effect to work.-->
<filter id="conform" x="-50%" y="-50%" width="200%" height="200%"> 
        
        <!-- Get the image. -->
        <feImage xlink:href="..." x="0" y="0" width="100%" height="100%" preserveAspectRatio="none"></feImage>
        
        <!-- Desaturate the image. -->
        <feColorMatrix type="saturate" values="0" result="IMAGE"/>

        <!-- decrease level of details so the effect on text is more realistic -->
        <feGaussianBlur in="IMAGE" stdDeviation="0.25" result="MAP"></feGaussianBlur>
        
        <!-- Use the displacement map to distort the source text -->
        <feDisplacementMap in="SourceGraphic" in2="MAP" scale="15" xChannelSelector="R" yChannelSelector="R" result="TEXTURED_TEXT"></feDisplacementMap>
        
        <!---->
        <feImage xlink:href="..." x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" result="BG"></feImage>
        
        <!-- Reduce the opacity of the text -->
        <feColorMatrix in="Textured_Text" result="Textured_Text_2" type="matrix" 
           values="1 0 0 0 0 
                   0 1 0 0 0 
                   0 0 1 0 0 
                   0 0 0 .9 0" />      

        <!-- Blend the text with the background -->
        <feBlend in="BG" in2="Textured_Text_2" mode="multiply" result="BLENDED_TEXT"></feBlend>

        <!-- Layer the text on top of the background image -->
        <feMerge>
            <feMergeNode in="BG"></feMergeNode>
            <feMergeNode in="BLENDED_TEXT"></feMergeNode>
        </feMerge>
</filter>

<text dx="60" dy="200" font-size="10em" font-weight="bold" filter="url(#conform)" fill="#00826C"> organic </text>

And this is our final result:

Screen Shot 2019-01-16 at 16.12.16

Notes about using Displacement Maps in SVG

The feDisplacementMap element has three attributes that determine how the displacement map will affect the source graphic:

  • xChannelSelector: specifies which color channel (R/G/B/A) from in2 to use for the horizontal displacement;
  • yChannelSelector: specifies which color channel (R/G/B/A) from in2 to use for the vertical displacement;
  • scale: determines the amount by which you want to distort the image. The higher the scale, the stronger the distortion effect is. You’ll probably find yourself experimenting with this value to get the desired result.

Possibly the most important thing to be aware of when using images to displace content in SVG filters is that the image and the content are subject to CORS rules. Make sure you’re serving both the image and the content from the same source to ensure that the browser does not skip the displacement operation.

You can also inline an image in the filter (in feImage) and use it as a displacement map. This pen by Gabi is a great example which uses an inlined SVG pattern to distort the source image. The circular pattern resulting in a ripple-like effect is my favorite.

Applying a Transformation to the Source Text

In the Photoshop tutorial that we followed for this effect, the designer applies a rotation transformation to the text that adds a nice touch to the overall effect.

If we apply a rotation transformation to the <text> to which we are applying the filter, the whole filter region will be rotated, including the image in the background:

Screen Shot 2019-01-16 at 19.32.58

This also happens if you apply other styles to the source text. For example, if you set the opacity on the <text> to 0.5, the text and the image in the background will also be affected by that.

In order to rotate the text but not the rest of the filter region, we can wrap the text in a group (<g>) and apply the filter to the group, and then apply the rotation transformation on the text. This will ensure that only the text is rotated, while the rest of the filter region, which is now defined by the group wrapper, remains unaffected by the transformation. This workaround is courtesy of Amelia Bellamy-Royds.

<g filter="url(#conform)">
     <text dx="60" dy="200" font-size="10em" transform="translate(-20 30) rotate(-7)" fill="#00826C">organic</text>
</g>

I’ve tweaked the transformation a little to add a translation to make sure the text remains centered in the filter region. The result of this transformation now looks like this:

Screen Shot 2019-01-16 at 19.40.50

Note that I’m applying the rotation transformation to the text using the SVG transform attribute and not via CSS because, at the time of writing of this article, Internet Explorer and MSEdge don’t support CSS transformations on SVG elements.

Live Demo

This text displacement effect currently works in all major browsers, including MSEdge. The following is a screenshot of the effect in MSEdge:

Screen Shot 2019-01-16 at 17.44.57

This said, Chrome has recently stopped applying the distortion effect on the text. There’s some more information about this issue in this thread. The rest of the filter operations, however, work and are applied just fine, so, until Chrome fixes this issue, you should be able to see the text blended with the background, only without the distortion along its edges. The following is a screenshot of what the demo looks like in Chrome:

Screen Shot 2019-01-16 at 18.06.57

You can check the live demo out here.

Final words

I hope you’re starting to enjoy the power of SVG filters and thinking of more possibilities and effects to create with them already.

If you liked the idea of conforming text to surface texture, then you’re going to love learning how to create your own texture in SVG. Yup, you read that right. SVG can create texture. In the next article, we’re going to learn how to create a simple texture using a combination of SVG-generated noise and lighting effects. Stay tuned.

SVG Filter Effects: Conforming Text to Surface Texture with <feDisplacementMap> was written by Sara Soueidan and published on Codrops.

SVG Filter Effects: Outline Text with <feMorphology>

SVGFilterEffects_Morphology_featured

Last week, in the first post of this series on SVG filter effects, we covered the basics of SVG filters—how to create them and how to use them. We also covered a few of the most frequently used filter operations (a.k.a. filter primitives). We will be reusing a little of what we covered in the first post in this article. So, unless you’re already familiar with those, I recommend taking a few minutes to read that article before moving forward with this one.

<feMorphology> is one of my favorite SVG filter operations. It is one of the simplest operations, too, and the results of applying it to different elements are predictable most of the time.

What is Morphing?

To morph means to transform or alter the form or the shape of an object.

The morphology filter operates on the form of an object. It provides two predefined shape transformations: erosion (a.k.a thinning, or shrinking) and dilation (a.k.a. thickening, or expanding). In other words, the feMorphology primitive can be used to shrink or expand elements.

Technically speaking, both these operations operate on a pixel level, expanding a pixel into its neighboring pixels (dilate) or crumbling the neighboring pixels at the edges of the pixel being operated on (erode), while still maintaining strokes around the edge of that pixel. The amount by which a pixel is dilated, or the number of neighboring pixels used to “stretch” or “expand” a pixel upon, is determined by a radius parameter.

<feMorphology 
    in=".." result=".." 
    operator="dilate || erode" radius="">
</feMorphology>

You can think of the morphing radius as the radius of a circle or ellipse; any neighboring pixels that lie within the circle determined by this radius and starting at the input pixel then counts as a neighboring pixel and will be used in the dilation or erosion effect.

In reality, though, the radius actually defines the size of a kernel known as the structuring element and which looks more like a matrix. For now, it’s enough to think about it in terms of a small rectangle whose width and height are determined in pixels specified in the radius attribute.

Effect of erosion using a 3x3 structuring element (kernel).

To use the filter we don’t need to get into the nerdy details of what morphing does on a pixel level. Suffice it to know that you can provide one or two radius values to feMorphology that will determine the amount by which your element will be shrunk or expanded. If you provide two numbers in the radius attribute, the first one will correspond to the x-radius and the second one will determine the y-radius.

Morphing Images

When the feMorphology operation is applied to images, it results in two, usually predictable, results:

  • The image size (dimensions) get smaller if the erode operator is used, and larger if the dilate operator is used.
  • With either operator, the image looks like it’s been painted with a large painting brush, with not a lot of fine detail in it.

So, assuming we want to apply the morphing effect to an image, our code would look as simple as this:

<svg width="450" height="300" viewBox="0 0 450 300">
    <filter id="erode">
        <feMorphology operator="erode" radius="3"></feMorphology>
    </filter>
    <image xlink:href="..." width="90%" height="90%" x="10" y="10" filter="url(#erode)"></image>
</svg>

In this snippet, we are eroding (shrinking) the (pixels in the) image by 3 pixels. The following image shows the result of this code. Notice how the size of the image is slightly smaller on the right:

The result (on the right) of applying the erode morphing effect to the image on the left.
The result (on the right) of applying the erode morphing effect to the image on the left.

Now, if we keep the same morph radius and change the operator from erode to dilate, the effect looks similar, but also distinctively different:

The result (on the right) of applying the dilate morph operation to the image on the left.
The result (on the right) of applying the dilate morph operation to the image on the left.

In both cases, the image looks like an abstract painted version of itself, and its overall size changes as its pixels expand or shrink.

But in addition to the these results, probably the first thing you’ll notice is the difference in colors resulting from each of these two effects: erode produces an image that has more dark pixels, whereas dilate produces a light output. This is due to the fact that:

  • erode (the default value) sets each pixel to its darkest or most transparent neighbor, respectively for each of the R, G, B, and A channels, and
  • dilate sets each channel of each pixel to match the brightest or least transparent value from its neighbors, for each channel respectively.

All this technicality aside, applying feMorphology to images will almost always have the same result: a shrunken or expanded low-detail paint-like version of the image with either dark or light main strokes.

See the Pen feMorphology on an image by Sara Soueidan (@SaraSoueidan) on CodePen.light

When applied to single-color elements, however, such as text, feMorphology only shrinks or expands the element—no noticeable pixel color changes happen because we only have one color to work with anyway…

Adding Colored Outline to Text with feMorphology

We can currently add an outline to text in SVG using the stroke attribute on that text.

<!-- Adding an outline to SVG text using strokes -->
<text font-size="80px" dx="100" dy="200" font-weight="700" stroke="deepPink" stroke-width="3px">Stroked Text</text>

By adding a stroke, the stroke is usually centered at the edges of the text so that half of its thickness overlaps with the text itself, making the text thinner, even when it’s not supposed to. Instead of reducing the thickness of the text to add an outline, we should be able to expand (or dilate) the text so that the thickness of the outline or stroke is added to that of the text. We can do that using feMorphology.

Unless otherwise styled, text usually comes in one color. So, applied to text, feMorphology allows us to shrink or thicken that text. Once the text is thickened using feMorphology, it can be used as input to other filter primitives which then allow us to create text outlines the way they are meant to be created.

Before we dig into how to do that, here is an image showing the difference between text with a stroke outline and an outline added using feMorphology.

Screen Shot 2019-01-08 at 13.39.46
Notice how the stroked text in the middle has become thinner after adding the stroke outline, compared to the text dilated using feMorphology.

So, let’s create a colored piece of text with an outline. We’ll take it step by step. This is the result we will be aiming for:

Screen Shot 2019-01-08 at 18.06.37

So we’ll start with an SVG containing our text and a filter that starts with a simple dilation operation. The amount you dilate the text by depends on the thickness of the outline that you want.

<svg width="900" height="200" viewBox="100 0 900 200">
    <filter id="outline">
        <feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="4"></feMorphology>
    </filter>

    <!-- DILATED TEXT -->
    <text font-size="85px" dx="125" dy="130" font-weight="700" filter="url(#outline)">upgrade yourself</text>
</svg>

The above code will get the alpha channel of the text—which is just a black version of the text—and will thicken it by 4px. The result of the code at this point looks like this:

Screen Shot 2019-01-08 at 18.10.25

..compared to the original text which has a dark navy blue fill color:

Screen Shot 2019-01-08 at 18.11.13

In order to create the outline effect, we will layer the original text on top of the dilated text, which will leave only the edges of the dilated text (the additional 4px) visible behind the original text, thus making them look like an outline. Overlaying the text on top of its outline (the dilated text) will be achieved using feMerge. We covered feMerge in the previous article.

Another thing we want to do before we position the outline behind the text is to colorize this outline. Also similar to what we did in the previous article, we will flood the filter region area with the color we want, and then composite the color layer with the dilated text layer (our outline) using the in operator. As a result, only the parts of the flood color that intersect with the dilated text will be rendered and the color will be blended with that text, thus colorizing it. Finally, we will merge the resulting colored outline with the original text to get the result we want. Our code now looks like this:

<svg width="900" height="200" viewBox="100 0 900 200">
    <filter id="outline">
        <feMorphology in="SourceAlpha" result="DILATED" operator="dilate" radius="4"></feMorphology>
        
        <feFlood flood-color="#32DFEC" flood-opacity="1" result="PINK"></feFlood>
        <feComposite in="PINK" in2="DILATED" operator="in" result="OUTLINE"></feComposite>

        <feMerge>
            <feMergeNode in="OUTLINE" />
            <feMergeNode in="SourceGraphic" />
        </feMerge>
    </filter>

    <!-- DILATED TEXT -->
    <text font-size="85px" dx="125" dy="130" font-weight="700" filter="url(#outline)">upgrade yourself</text>
</svg>

Creating a filter effect in SVG is a matter of thinking of the final result in terms of smaller operations, and using the result of one operation as input to another, and finally merging any layers we have created to achieve the final result.

The following is a live demo of the above code:

See the Pen Colored Text Outline with feMorphology by Sara Soueidan (@SaraSoueidan) on CodePen.light

The fill color of the text can be specified either in your CSS or on the text element using the fill attribute. The color of the outline can be tweaked in the flood-color attribute of the feFlood primitive.

Knocking the Text Out

In addition to adding an outline to text by dilating its alpha channel and layering it behind the text, we can create outline-only text, a.k.a. knockout text, meaning that the inside of the text will be “carved out” so you can see the background behind it through the outline. An example of such effect might look like the text in the following GIF, which shows a background changing color, and how that background can be seen within our text. This is the demo we will be creating in this section:

bird-GIF-svg

This effect is easier to create, and the code required to make it is noticeably shorter. The main difference here is that instead of layering the source text on top of the dilated text, we will use that source text to cut out the inner parts of the dilated text. This means that only the added thickness of the dilated text will remain, while the inside will be removed, thus giving us our outline.

We can do that by compositing the source text with the dilated text. Our source text will go on top, and the dilated text will be its backdrop. Using the out composite operator, only the parts of the backdrop that do not overlap with the source layer will be rendered, which in our case means that only our outline will be rendered.

<svg width="900" height="450" viewBox="0 0 900 450">
    <filter id="outliner">

        <!-- Start by grabbing the alpha channel of the text and dilating it-->
        <feMorphology operator="dilate" radius="8" in="SourceAlpha" result="THICKNESS" />
        
         <!-- Next, grab the original text (SourceGraphic) and use it to cut out the inside of the dilated text -->
        <feComposite operator="out" in="THICKNESS" in2="SourceGraphic"></feComposite>
    </filter>

    <text dx="100" dy="300" filter="url(#outliner)" letter-spacing="10px">SVG Rocks</text>
</svg>

Using a nice font face, our demo now looks like this:

Screen Shot 2019-01-08 at 18.33.21

Cool. Now, what if you want to change the color of the outline? You’d have to use the feFlood primitive again and composite the Flood color with the outline. And then every time you want to change the color of the outline, you’d have to do the same over and over again. This is, admittedly, too tedious. Fortunately, there is a simpler way.

If instead of grabbing and dilating the alpha channel of the text (which is black by default) you grab the source text itself (which could have any fill color!) and dilate it, and then use the text again to carve out the inside of the dilated text, you end up with an outline that comes from the source text itself. This means that the color of that outline will always be the same as the color of the source text. And since we can define the fill color of the source text in CSS, this means that you have an outline text that is separated from its styles. (Yay separation of concerns!) You can then apply the filter to any piece of text, and change the color of that text in the CSS any time you need to, without having to tweak the filter’s code. Our improved code now looks like this:

<svg width="900" height="450" viewBox="0 0 900 450">
    <filter id="outliner">

        <!-- Start by grabbing the source graphic (the text) and dilating it-->
        <feMorphology operator="dilate" radius="8" in="SourceGraphic" result="THICKNESS" />
        
         <!-- Then use the text (the SourceGraphic) again to cut out the inside of the dilated text -->
        <feComposite operator="out" in="THICKNESS" in2="SourceGraphic"></feComposite>
    </filter>

    <text dx="100" dy="300" filter="url(#outliner)" letter-spacing="10px">SVG Rocks</text>
</svg>

In our style sheet, we can choose the outline color as well as the SVG background color. You can also choose to have an image behind the text inside the SVG. I’m using CSS animations in the code below to animate the color of the background, for no reason other than it being cool.

svg text {
    font-family: 'Bangers', cursive;
    font-size: 150px;
    letter-spacing: 13px;
    fill: #000; /* This fill color determines the color of the outline */
}

svg {
    background-color: gold;
    animation: colorsssss 2s linear infinite;
    animation-delay: 3s;
}

@keyframes colorsssss {
    50% {
        background-color: deepPink;
    }
}

The above SVG filter is reusable across SVG as well as HTML. If you want to apply it to an HTML element, you can do that using the filter property; just place the filter in your HTML and “call” it in your CSS:

h2 {
    filter: url(#outliner);

    /* You can change the color of the outline here by changing the color of the heading */
    color: deepPink;
}

And our finished demo that includes an HTML heading with the filter applied to it:

See the Pen (Text) Outlines (Only) by Sara Soueidan (@SaraSoueidan) on CodePen.light

My favorite thing about this filter recipe is that it can be used as a visual enhancement. If a browser does not support SVG filters, or if it does not support CSS filters, or it does not support applying SVG filters to HTML elements, the user will get the original text without the outline/knockout effect applied to it. Oh, and the cherry on top of the cake? Both the SVG and the HTML text will be fully accessible, searchable and selectable. Yay progressive enhancement! Yay SVG!

Final Words

Using just two filter operations in SVG, you can apply an outlined text effect to your SVG or HTML text content. Place this filter in your HTML and use and reuse it as often as you need.

In the next article in this series, we will have a look at the <feComponentTransfer>, one of my favorite filter primitives, and see how it works and what effects we can create with it. Stay tuned.

SVG Filter Effects: Outline Text with <feMorphology> was written by Sara Soueidan and published on Codrops.