{"id":3896,"date":"2024-09-20T14:35:26","date_gmt":"2024-09-20T19:35:26","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=3896"},"modified":"2024-09-20T14:35:27","modified_gmt":"2024-09-20T19:35:27","slug":"gradient-text-with-a-drop-shadow","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/gradient-text-with-a-drop-shadow\/","title":{"rendered":"Gradient Text with a Drop Shadow"},"content":{"rendered":"\n<p>During our annual promotion, we had this branding for the countdown timer:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"376\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/sale.jpg?resize=800%2C376&#038;ssl=1\" alt=\"\" class=\"wp-image-3898\" style=\"width:603px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/sale.jpg?w=800&amp;ssl=1 800w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/sale.jpg?resize=300%2C141&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/sale.jpg?resize=768%2C361&amp;ssl=1 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/figure>\n<\/div>\n\n\n<p>The &#8220;Ends in X days!&#8221; needed to be HTML text since it&#8217;s dynamic based on the sale end date. Note that it both colored with a gradient and has both a stroke and a drop shadow.<\/p>\n\n\n\n<p>We can achieve a text gradient by clipping the background to the text with <code>background-clip: text<\/code>, like this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.Countdown<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: <span class=\"hljs-built_in\">linear-gradient<\/span>(#fff000, #ff3600);\n  <span class=\"hljs-attribute\">background-clip<\/span>: text;\n  <span class=\"hljs-attribute\">-webkit-background-clip<\/span>: text;\n  <span class=\"hljs-attribute\">color<\/span>: transparent;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This creates a gradient background and then clips the background to the text. Then we hide the actual text itself with <code>color: transparent<\/code>. Here&#8217;s the demo:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_GRVKpbj\" src=\"\/\/codepen.io\/anon\/embed\/GRVKpbj?height=300&amp;theme-id=47434&amp;slug-hash=GRVKpbj&amp;default-tab=result\" height=\"300\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed GRVKpbj\" title=\"CodePen Embed GRVKpbj\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Now I want to add a shadow behind it&#8230; sounds simple, right? Of course not. <\/p>\n\n\n\n<p>The obvious way, using <code>text-shadow<\/code>, looks bad because <code>color: transparent<\/code> makes the text itself transparent, and the shadow it renders is actually <em>above<\/em> the background we&#8217;re setting.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_MWNgKxN\" src=\"\/\/codepen.io\/anon\/embed\/MWNgKxN?height=350&amp;theme-id=47434&amp;slug-hash=MWNgKxN&amp;default-tab=result\" height=\"350\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed MWNgKxN\" title=\"CodePen Embed MWNgKxN\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>So that&#8217;s out.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Pseudo Element Solution: Gradient Text with a Drop Shadow<\/h2>\n\n\n\n<p>We can use a pseudo element that replicates the text and layers itself behind the background of the main text, and we can then use <code>text-shadow<\/code> on <em>that<\/em> safely:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.Countdown<\/span><span class=\"hljs-selector-pseudo\">::before<\/span> {\n  <span class=\"hljs-attribute\">content<\/span>: <span class=\"hljs-built_in\">attr<\/span>(data-text);\n  <span class=\"hljs-attribute\">position<\/span>: absolute;\n  <span class=\"hljs-attribute\">left<\/span>: <span class=\"hljs-number\">0<\/span>;\n  <span class=\"hljs-attribute\">top<\/span>: <span class=\"hljs-number\">0<\/span>;\n  <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n  <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">100%<\/span>;\n  <span class=\"hljs-attribute\">z-index<\/span>: -<span class=\"hljs-number\">1<\/span>;\n  <span class=\"hljs-attribute\">color<\/span>: <span class=\"hljs-number\">#000<\/span>;\n  <span class=\"hljs-attribute\">text-shadow<\/span>: -<span class=\"hljs-number\">4px<\/span> <span class=\"hljs-number\">4px<\/span> <span class=\"hljs-number\">1px<\/span> <span class=\"hljs-number\">#000<\/span>, <span class=\"hljs-number\">3px<\/span> <span class=\"hljs-number\">2px<\/span> <span class=\"hljs-number\">1px<\/span> <span class=\"hljs-number\">#000<\/span>, -<span class=\"hljs-number\">1px<\/span> -<span class=\"hljs-number\">2px<\/span> <span class=\"hljs-number\">1px<\/span> <span class=\"hljs-number\">#000<\/span>, <span class=\"hljs-number\">2px<\/span> <span class=\"hljs-number\">6px<\/span> <span class=\"hljs-number\">3px<\/span> <span class=\"hljs-number\">#000<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Note the multiple shadows are in multiple directions simulating stroked text.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_GRVKZRd\" src=\"\/\/codepen.io\/anon\/embed\/GRVKZRd?height=450&amp;theme-id=47434&amp;slug-hash=GRVKZRd&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed GRVKZRd\" title=\"CodePen Embed GRVKZRd\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>It&#8217;s not ideal since we also have to add the text to the <code>data<\/code> attribute in order to be inserted into the pseudo element:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"Countdown CountdownFont\"<\/span> \n  <span class=\"hljs-attr\">data-text<\/span>=<span class=\"hljs-string\">\"Ends in 7 days\"<\/span>&gt;<\/span>\n  Ends in 7 days\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That is repetitive, heavier, and error-prone. It also means that if you need to change the text contents via JavaScript, you&#8217;ll also need to keep the <code>data<\/code> attribute updated as well. Not to mention negative <code>z-index<\/code> can have trouble when there is other elements backgrounds involved.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SVG Solution: Gradient Text with a Drop Shadow<\/h2>\n\n\n\n<p>Although it&#8217;s the most complex of the methods, you can apply both effects to an SVG, no problem!<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_RwXbaGy\" src=\"\/\/codepen.io\/anon\/embed\/RwXbaGy?height=450&amp;theme-id=47434&amp;slug-hash=RwXbaGy&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed RwXbaGy\" title=\"CodePen Embed RwXbaGy\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>In the code we use the <code>linearGradient<\/code> SVG element to draw the text, and a series of <code>feDropShadow<\/code> filters to the text span element:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">svg<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"auto\"<\/span> <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"auto\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">defs<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">linearGradient<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"gradient\"<\/span> <span class=\"hljs-attr\">x1<\/span>=<span class=\"hljs-string\">\"0%\"<\/span> <span class=\"hljs-attr\">y1<\/span>=<span class=\"hljs-string\">\"0%\"<\/span> <span class=\"hljs-attr\">x2<\/span>=<span class=\"hljs-string\">\"0%\"<\/span> <span class=\"hljs-attr\">y2<\/span>=<span class=\"hljs-string\">\"100%\"<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">stop<\/span> <span class=\"hljs-attr\">offset<\/span>=<span class=\"hljs-string\">\"0%\"<\/span> <span class=\"hljs-attr\">stop-color<\/span>=<span class=\"hljs-string\">\"#fff000\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">stop<\/span> <span class=\"hljs-attr\">offset<\/span>=<span class=\"hljs-string\">\"100%\"<\/span> <span class=\"hljs-attr\">stop-color<\/span>=<span class=\"hljs-string\">\"#ff3600\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">linearGradient<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">defs<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">filter<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"shadow\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">feDropShadow<\/span> <span class=\"hljs-attr\">dx<\/span>=<span class=\"hljs-string\">\"-4\"<\/span> <span class=\"hljs-attr\">dy<\/span>=<span class=\"hljs-string\">\"4\"<\/span> <span class=\"hljs-attr\">stdDeviation<\/span>=<span class=\"hljs-string\">\"1\"<\/span> <span class=\"hljs-attr\">flood-color<\/span>=<span class=\"hljs-string\">\"black\"<\/span> <span class=\"hljs-attr\">flood-opacity<\/span>=<span class=\"hljs-string\">\"0.5\"<\/span>\/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">feDropShadow<\/span> <span class=\"hljs-attr\">dx<\/span>=<span class=\"hljs-string\">\"3\"<\/span> <span class=\"hljs-attr\">dy<\/span>=<span class=\"hljs-string\">\"2\"<\/span> <span class=\"hljs-attr\">stdDeviation<\/span>=<span class=\"hljs-string\">\"2\"<\/span> <span class=\"hljs-attr\">flood-color<\/span>=<span class=\"hljs-string\">\"black\"<\/span> <span class=\"hljs-attr\">flood-opacity<\/span>=<span class=\"hljs-string\">\"0.5\"<\/span>\/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">feDropShadow<\/span> <span class=\"hljs-attr\">dx<\/span>=<span class=\"hljs-string\">\"-1\"<\/span> <span class=\"hljs-attr\">dy<\/span>=<span class=\"hljs-string\">\"-2\"<\/span> <span class=\"hljs-attr\">stdDeviation<\/span>=<span class=\"hljs-string\">\"1\"<\/span> <span class=\"hljs-attr\">flood-color<\/span>=<span class=\"hljs-string\">\"black\"<\/span> <span class=\"hljs-attr\">flood-opacity<\/span>=<span class=\"hljs-string\">\"0.5\"<\/span>\/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">feDropShadow<\/span> <span class=\"hljs-attr\">dx<\/span>=<span class=\"hljs-string\">\"2\"<\/span> <span class=\"hljs-attr\">dy<\/span>=<span class=\"hljs-string\">\"6\"<\/span> <span class=\"hljs-attr\">stdDeviation<\/span>=<span class=\"hljs-string\">\"3\"<\/span> <span class=\"hljs-attr\">flood-color<\/span>=<span class=\"hljs-string\">\"black\"<\/span> <span class=\"hljs-attr\">flood-opacity<\/span>=<span class=\"hljs-string\">\"0.5\"<\/span>\/&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">filter<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">text<\/span> <span class=\"hljs-attr\">x<\/span>=<span class=\"hljs-string\">\"10\"<\/span> <span class=\"hljs-attr\">y<\/span>=<span class=\"hljs-string\">\"50\"<\/span> <span class=\"hljs-attr\">font-family<\/span>=<span class=\"hljs-string\">\"Rubik Mono One\"<\/span> <span class=\"hljs-attr\">font-size<\/span>=<span class=\"hljs-string\">\"40\"<\/span> <span class=\"hljs-attr\">fill<\/span>=<span class=\"hljs-string\">\"url(#gradient)\"<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">tspan<\/span> <span class=\"hljs-attr\">filter<\/span>=<span class=\"hljs-string\">\"url(#shadow)\"<\/span>&gt;<\/span>Ends in 7 Days<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">tspan<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">text<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">svg<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The nice thing here is there&#8217;s only one place to change the text, and the text remains selectable and accessible like any other web text. Do note that <em>wrapping<\/em> SVG <code>&lt;text><\/code> isn&#8217;t particularly well supported and probably best to avoid.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Other Examples in the Wild<\/h2>\n\n\n\n<p>I did find this quick shot of gradient text and text shadow a nice reference of types of effects:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_vMavPr\" src=\"\/\/codepen.io\/anon\/embed\/vMavPr?height=450&amp;theme-id=47434&amp;slug-hash=vMavPr&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed vMavPr\" title=\"CodePen Embed vMavPr\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Finally, Ana Tudor has some wild CodePens blending tons of SVG Filters together to make wild text effects:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_gONbppb\" src=\"\/\/codepen.io\/anon\/embed\/gONbppb?height=450&amp;theme-id=47434&amp;slug-hash=gONbppb&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed gONbppb\" title=\"CodePen Embed gONbppb\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Have fun!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Gradient text is pretty easy to do these days with `background-clip: text;` \u2014 but it kills your ability to use `text-shadow`. SVG to the rescue. <\/p>\n","protected":false},"author":2,"featured_media":3924,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[7,91,39],"class_list":["post-3896","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-css","tag-svg","tag-typography"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/09\/shadow.jpg?fit=942%2C637&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3896","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=3896"}],"version-history":[{"count":14,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3896\/revisions"}],"predecessor-version":[{"id":3923,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/3896\/revisions\/3923"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/3924"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=3896"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=3896"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=3896"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}