Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <h1>Photoshop-Style Drop-Shadows Using Web filters </h1>
<div class="summary">This demo uses SVG filters to duplicate PhotoShop's drop shadow control. </br></br>
  
Things to note: applying an SVG filter to HTML text via a CSS filter clips the shadow to a specific region around HTML text (In SVG, this region's size is configurable). 

Browser errata: Safari: CSS filters don't yet support SVG compositing so it won't show a drop shadow on the HTML text. IE: while the output works fine on SVG text, IE doesn't support CSS filters yet, and the form inputs below don't quite work (range and event detection problems).</div>

<table id="master-container">
<tr>
  <td id="text-container">
  <svg height="200px" width="300px" viewbox="0 0 300 200">
    <defs>
      <filter id="drop-shadow" color-interpolation-filters="sRGB" x="-50%" y="-50%" height="200%" width="200%">

<!-- Take source alpha, offset it by angle/distance and blur it by size     -->
        <feOffset id="offset" in="SourceAlpha" dx="3.54" dy="3.54" result="SA-offset"/>
        <feGaussianBlur id="blur" in="SA-offset" stdDeviation="3" result="SA-o-blur"/>
        
<!-- Apply a contour by using a color curve transform on the alpha and clipping the result to the input  -->        
        <feComponentTransfer in="SA-o-blur" result="SA-o-b-contIN">
          <feFuncA id="contour" type="table" tableValues="0 1"/>
        </feComponentTransfer>
        
        <feComposite operator="in" in="SA-o-blur" in2="SA-o-b-contIN" result="SA-o-b-cont"/>
        
<!-- Adjust the spread by multiplying alpha by a constant factor      -->          
        <feComponentTransfer in="SA-o-b-cont" result="SA-o-b-c-sprd">
          <feFuncA id="spread-ctrl" type="linear" slope="1"/>
        </feComponentTransfer>        
        
        
<!-- Adjust color and opacity by adding fixed offsets and an opacity multiplier --> 
        
         <feColorMatrix id="recolor" in="SA-o-b-c-sprd" type="matrix" 
                                                      values="1 0 0 0 0
                                                              0 1 0 0 0
                                                              0 0 1 0 0 
                                                              0 0 0 .8 0"
                       result="SA-o-b-c-s-recolor"/>       
        
<!-- Generate a reasonably grainy noise input with baseFrequency of .5 to 2.0, and add the noise with a k1 multiplier, and a k2 that add to 1 -->         
        <feTurbulence result="fNoise" type="fractalNoise" numOctaves="6" baseFrequency="1.98"/>
        <feColorMatrix in="fNoise" type="matrix" values="1 0 0 0 0
                                                         0 1 0 0 0
                                                         0 0 1 0 0 
                                                         0 0 0 7 -3"
                                         result="clipNoise"/>
        <feComposite id="noisemix" operator="arithmetic" in="SA-o-b-c-s-recolor" in2="clipNoise" k1="0" k2="1" result="SA-o-b-c-s-r-mix"/>
        
<!-- Merge the shadow with the original --> 
        
        <feMerge>
          <feMergeNode in="SA-o-b-c-s-r-mix"/>
          <feMergeNode in="SourceGraphic"/>
        </feMerge>
      </filter>
    </defs>
    <text filter="url(#drop-shadow)" x="70" y="100">SVG </text>
    <text filter="url(#drop-shadow)" x="70" y="180">Text</text>
                              
  </svg>
    <h2>HTML</h2>
    <h2>Text</h2>
  </td>
  <td>
  
<div id="control-container">
  <table>
     <tr>
      <td>Color</td>
      <td><input type="color" id="drop-color" value="#000000"/>
      </td>
    </tr>
    <tr>
      <td>Opacity %</td>
      <td><input type="range" id="drop-opacity" min="0" max="1" step=".01" value=".8"/>
      </td>
    </tr>   
    <tr>
      <td>Angle (deg)</td>
      <td><input type="range" id="drop-angle" min="0" max="360" step="1" value="135"/>
      </td>
    </tr>
    <tr>
      <td>Distance (px)</td>
      <td><input type="range" id="drop-dist" min="0" max="40" step="0.5" value="5"/>
      </td>
    </tr>   
    <tr>
      <td>Spread (x)</td>
      <td><input type="range" id="drop-spread" min="0" max="1" step="0.01" value="0"/>
      </td>
    </tr>   
    <tr>
      <td>Size (px)</td>
      <td><input type="range" id="drop-size" min="1" max="15" step="0.25" value="3"/>
      </td>
    </tr>   
    <tr>
      <td valign="top" style="padding-top:8px">Contour</td>
      <td style="padding-left:8px">
        <svg width="160px" height="120px" viewbox="0 0 160 120">
          
          <!--Contour boxes -->
          
           <!--Row 1 -->
           <rect stroke="#333" fill="white" x="7%" y="9%" width="19%" height="26%"/> 
            <path  d="M13,40 l26,-28 0,28z"  fill="#333"/>
           <rect stroke="#333" fill="white"  x="29%" y="9%" width="19%" height="26%"/> 
             <path  d="M48,40 Q62,-13 75,40z"  fill="#333"/>
           <rect stroke="#333" fill="white"  x="51%" y="9%" width="19%" height="26%"/> 
            <path  d="M83,14 Q95.5,58 110,14 l0,26 -27,0z"  fill="#333"/>
           <rect stroke="#333" fill="white"  x="73%" y="9%" width="19%" height="26%"/> 
            <path  d="M119,30 q15,00 18,-16 l8,0 0,26 -26,0z" fill="#333"/>
          
            <!--Row 2 -->
            <rect stroke="#333" fill="white" x="7%" y="40%" width="19%" height="26%"/> 
            <path  d="M13,62 q7,0 12,-11 l14,0 0,26 -26,0z" fill="#333"/>
           <rect stroke="#333" fill="white"  x="29%" y="40%" width="19%" height="26%"/> 
             <path  d="M48,77 q9,0 13,-13 t13,-13 l0,26z"  fill="#333"/>
           <rect stroke="#333" fill="white"  x="51%" y="40%" width="19%" height="26%"/> 
            <path  d="M83,77 q7,-26 26,-26 l0,26z"  fill="#333"/>
           <rect stroke="#333" fill="white"  x="73%" y="40%" width="19%" height="26%"/> 
            <path  d="M118,77 q4,-6 4.5,-13 t4.5,-13 q4,6 4.5,13 t4.5,13 q4,-6 4.5,-13 t4.5,-13  l0,26z" fill="#333"/>
 

             <!--Row 3 -->        
           <rect stroke="#333" fill="white" x="7%" y="71%" width="19%" height="26%"/> 
            <path  d="M12,114 
                      q3,-10 3,-17 t3,-9   
                      q3,3 3,9 t3,17 
                      q3,-10 2.5,-17 t2.5,-9      
                      q3,3 2.5,9 t2.5,17 
                      q3,-10 3,-17 t3,-9 
                      l0,26z"  fill="#333"/>
           <rect stroke="#333" fill="white"  x="29%" y="71%" width="19%" height="26%"/> 
             <path  d="M48,88 c10,40 15,-15 26,26 l-26,0z" fill="#333"/>   
          <rect stroke="#333" fill="white"  x="51%" y="71%" width="19%" height="26%"/> 
            <path  d="M83,114 q0,-9 7,-9 q0,-7 7,-7 q0,-5 6,-5 q0,-3 6,-3 l0,24z"  fill="#333"/>
           <rect stroke="#333" fill="white"  x="73%" y="71%" width="19%" height="26%"/> 
            <path  d="M118,114 l7,-13 7,13,7,-13,7,13z" fill="#333"/>
          
          <!--Overlay boxes to capture clicks -->
           <!--Row 1 -->
           <rect id="contour-0" fill-opacity=".01" x="7%" y="9%" width="19%" height="26%"/>
           <rect id="contour-1" fill-opacity=".2"  x="29%" y="9%" width="19%" height="26%"/> 
           <rect id="contour-2" fill-opacity=".2"  x="51%" y="9%" width="19%" height="26%"/> 
           <rect id="contour-3" fill-opacity=".2"  x="73%" y="9%" width="19%" height="26%"/>
            <!--Row 2 -->
           <rect id="contour-4" fill-opacity=".2" x="7%" y="40%" width="19%" height="26%"/> 
           <rect id="contour-5" fill-opacity=".2"  x="29%" y="40%" width="19%" height="26%"/> 
           <rect id="contour-6" fill-opacity=".2"  x="51%" y="40%" width="19%" height="26%"/> 
           <rect id="contour-7" fill-opacity=".2"  x="73%" y="40%" width="19%" height="26%"/> 
           <!--Row 3 -->        
           <rect  id="contour-8" fill-opacity=".2" x="7%" y="71%" width="19%" height="26%"/> 
           <rect  id="contour-9" fill-opacity=".2"  x="29%" y="71%" width="19%" height="26%"/> 
           <rect  id="contour-10" fill-opacity=".2"  x="51%" y="71%" width="19%" height="26%"/> 
           <rect  id="contour-11" fill-opacity=".2"  x="73%" y="71%" width="19%" height="26%"/> 


        </svg>
      </td>
    </tr>   
    <tr>
       <td>Noise %</td>
      <td><input type="range" id="drop-noise" min="0" max="1" step="0.01" value="0"/>
      </td>
    </tr>
  
  </table>
  </td>
  </tr>
</table>
  
  
 <div id="filter-code">
   <p>
        &lt;filter id=&quot;drop-shadow&quot; color-interpolation-filters=&quot;sRGB&quot; x=&quot;-50%&quot; y=&quot;-50%&quot; height=&quot;200%&quot; width=&quot;200%&quot;&gt;
   </p>
&lt;!-- Take source alpha, offset it by angle/distance and blur it by size     --&gt;
       <p>    &lt;feOffset id=&quot;offset&quot; in=&quot;SourceAlpha&quot; dx=&quot;<span id="dispdx">3.54</span>&quot; dy=&quot;<span id="dispdy">3.54</span>&quot; result=&quot;SA-offset&quot;/&gt;
      </br>
        &lt;feGaussianBlur id=&quot;blur&quot; in=&quot;SA-offset&quot; stdDeviation=&quot;<span id="dispsize">3</span>&quot; result=&quot;SA-o-blur&quot;/&gt;
    <p>       
&lt;!-- Apply a contour by using a color curve transform on the alpha and clipping the result to the input --&gt;        
  <p>      &lt;feComponentTransfer in=&quot;SA-o-blur&quot; result=&quot;SA-o-b-contIN&quot;&gt;
 </br>      &nbsp;    &lt;feFuncA id=&quot;contour&quot; type=&quot;table&quot; tableValues=&quot;<span id="dispcontour">0 1</span>&quot;/&gt;
      </br>      &lt;/feComponentTransfer&gt;
        
<p>        &lt;feComposite operator=&quot;in&quot; in=&quot;SA-o-blur&quot; in2=&quot;SA-o-b-contIN&quot; result=&quot;SA-o-b-cont&quot;/&gt;
        
<p>  &lt;!-- Adjust the spread by multiplying alpha by a constant factor      --&gt;          
        &lt;feComponentTransfer in=&quot;SA-o-b-cont&quot; result=&quot;SA-o-b-c-sprd&quot;&gt;
    </br> &nbsp;      &lt;feFuncA id=&quot;spread-ctrl&quot; type=&quot;linear&quot; slope=&quot;<span id="dispspread">1</span>&quot;/&gt;
    </br>      &lt;/feComponentTransfer&gt;        
        
        
   <p>  &lt;!-- Adjust color and opacity by adding fixed offsets and an opacity multiplier --&gt; 
        
 </br>          &lt;feColorMatrix id=&quot;recolor&quot; in=&quot;SA-o-b-c-sprd&quot; type=&quot;matrix&quot; 
                                                      values=&quot;<span id="dispcolmatrix"/>1 0 0 0 0
                                                              0 1 0 0 0
                                                              0 0 1 0 0 
   0 0 0 .8 0</span>&quot;
                       result=&quot;SA-o-b-c-s-recolor&quot;/&gt;       
        
<p>  &lt;!-- Generate a reasonably grainy noise input with baseFrequency between approx .5 to 2.0. And add the noise with k1 and k2 multipliers that sum to 1 --&gt;         
    </br>      &lt;feTurbulence result=&quot;fNoise&quot; type=&quot;fractalNoise&quot; numOctaves=&quot;6&quot; baseFrequency=&quot;1.98&quot;/&gt;
     </br>     &lt;feColorMatrix in=&quot;fNoise&quot; type=&quot;matrix&quot; values=&quot;1 0 0 0 0
                                                         0 1 0 0 0
                                                         0 0 1 0 0 
                                                         0 0 0 7 -3&quot;
                                         result=&quot;clipNoise&quot;/&gt;
      </br>    &lt;feComposite id=&quot;noisemix&quot; operator=&quot;arithmetic&quot; in=&quot;SA-o-b-c-s-recolor&quot; in2=&quot;clipNoise&quot; k1=&quot;<span id="dispk1">0</span>&quot; k2=&quot;<span id="dispk2">1</span>&quot; result=&quot;SA-o-b-c-s-r-mix&quot;/&gt;
        
<p>  &lt;!-- Merge the shadow with the original --&gt; 
        
  </br>         &lt;feMerge&gt;
   </br> &nbsp;         &lt;feMergeNode in=&quot;SA-o-b-c-s-r-mix&quot;/&gt;
  </br>  &nbsp;     &lt;feMergeNode in=&quot;SourceGraphic&quot;/&gt;
  </br>      &lt;/feMerge&gt;
  </br>    &lt;/filter&gt;
  </div>
              
            
!

CSS

              
                H1 {
    font-family: sans-serif;
    position: relative;
    left: 12%;
}

H2 {
    font-family: sans-serif;
    position: relative;
    left: 60px;
    font-size: 4.5em;
    line-height: 0.3em;
    -webkit-filter: url(#drop-shadow);
    -moz-filter: url(#drop-shadow);
    -ms-filter: url(#drop-shadow);
    filter: url(#drop-shadow);
}

div {
  font-family: sans-serif;
}

#master-container {
  position: relative;
  left: 16%;
}

#control-container{
  left: 50px;
  width: 300px;
  background-color: #aaa;
  border: 10px solid #aaa;
  padding: 5px;
}

#text-container{
  position: relative;
  width: 300px;
  border: 1px solid #bbb;
}

.summary {
  position:relative ;
  width:600px;
  left: 16%;
  margin: 40px;

}

#filter-code {
  font-family: monospace;
  position: relative;
  padding: 16px;
  left: 14%;
  width: 700px;
}

td {
  padding:3px;
  font-family: sans-serif;
}


svg{
  font-size: 4em;
  font-family: arial;
  font-weight: bold;
}


input[type=range] {
    width: 150px;
    height: 10px;
    margin: 10px 0 10px 10px;
}

input[type=color] {
    width: 150px;
    margin: 10px 0 9px 10px;
}


              
            
!

JS

              
                 //Set up variables for form inputs and add change handlers

    var colorInput = document.getElementById("drop-color");
    var opacInput = document.getElementById("drop-opacity");
    var angleInput = document.getElementById("drop-angle");
    var distInput = document.getElementById("drop-dist");
    var spreadInput = document.getElementById("drop-spread");
    var sizeInput= document.getElementById("drop-size");
    var noiseInput= document.getElementById("drop-noise");
    
   var contourInput = new Array(12);
     contourInput[0]=document.getElementById("contour-0");
     contourInput[1]=document.getElementById("contour-1");
     contourInput[2]=document.getElementById("contour-2");
     contourInput[3]=document.getElementById("contour-3");
     contourInput[4]=document.getElementById("contour-4");
     contourInput[5]=document.getElementById("contour-5");
     contourInput[6]=document.getElementById("contour-6");
     contourInput[7]=document.getElementById("contour-7");
     contourInput[8]=document.getElementById("contour-8");
     contourInput[9]=document.getElementById("contour-9");
     contourInput[10]=document.getElementById("contour-10");
     contourInput[11]=document.getElementById("contour-11");

   contourInput[0].addEventListener('click', function(){changeContour("0")}, false);
   contourInput[1].addEventListener('click', function(){changeContour("1")}, false);
   contourInput[2].addEventListener('click', function(){changeContour("2")}, false);
   contourInput[3].addEventListener('click', function(){changeContour("3")}, false);
   contourInput[4].addEventListener('click', function(){changeContour("4")}, false);
   contourInput[5].addEventListener('click', function(){changeContour("5")}, false);
   contourInput[6].addEventListener('click', function(){changeContour("6")}, false);
   contourInput[7].addEventListener('click', function(){changeContour("7")}, false);
   contourInput[8].addEventListener('click', function(){changeContour("8")}, false);
   contourInput[9].addEventListener('click', function(){changeContour("9")}, false);
   contourInput[10].addEventListener('click', function(){changeContour("10")}, false);
   contourInput[11].addEventListener('click', function(){changeContour("11")}, false);

  var activeContour="0";

    colorInput.addEventListener('input', changeColor, false);
    opacInput.addEventListener('input', changeColor, false);
    angleInput.addEventListener('input', changeOffset, false);
    distInput.addEventListener('input', changeOffset, false);
    spreadInput.addEventListener('input', changeShadow, false);
    sizeInput.addEventListener('input', changeShadow, false);
    noiseInput.addEventListener('input', changeShadow, false);


//  Setup variables for filter primitives
    var colMatrixPrim = document.getElementById("recolor");
    var offsetPrim = document.getElementById("offset");
    var spreadPrim = document.getElementById("spread-ctrl");
    var sizePrim = document.getElementById("blur");
    var contourPrim = document.getElementById("contour");
    var noisePrim = document.getElementById("noisemix");

// Setup variables for source code text
    var dispDX = document.getElementById("dispdx");
    var dispDY = document.getElementById("dispdy");
    var dispSPREAD = document.getElementById("dispspread");
    var dispSIZE = document.getElementById("dispsize");
    var dispK1 = document.getElementById("dispk1");
    var dispK2 = document.getElementById("dispk2");
    var dispCONTOUR = document.getElementById("dispcontour");
    var dispCOLMATRIX = document.getElementById("dispcolmatrix");


//  Setup variables for array of contour values
    var contourArrays = new Array(11);
      contourArrays[0]="0 1";
      contourArrays[1]="0 .1 .5 .8 .9 1 .9 .8 .5 .1 0";
      contourArrays[2]="0 1 .3 .1 0.05 .1 .3 1 ";
      contourArrays[3]="0 0.4 0.45 0.5 0.62 0.87 1 1";
      contourArrays[4]="0.65 0.68 0.75 0.95 1 1 1 ";
      contourArrays[5]="0 0.05 0.15 0.4 0.5 0.6 0.85 0.95 1";
      contourArrays[6]="0 0.2 0.45 0.6 0.7 0.8 0.85 0.9 0.95 1 ";
      contourArrays[7]="0 0.05 0.15 0.45 0.7 0.85 0.95 1 0.95 0.85 0.7 0.45 0.15 0.05 0 0.05 0.15 0.45 0.7 0.85 0.95 1";
      contourArrays[8]="0 0.05 0.15 0.45 0.7 0.85 0.95 1 0.95 0.85 0.7 0.45 0.15 0.05 0 0.05 0.15 0.45 0.7 0.85 0.95 1 0.95 0.85 0.7 0.45 0.15 0.05 0 0.05 0.15 0.45 0.7 0.85 0.95 1";
      contourArrays[9]="0 1 0.65 0.5 0.55 0.6 0.65 0.55 0.4 0.1 0";
      contourArrays[10]="0 0.2 0.25 0.4 0.45 0.6 0.65 0.8 0.85";
      contourArrays[11]="0 .5 0 .5 0";

//  Functions

    function changeColor() {
      var redVal=Math.round(((hexToRgb(colorInput.value).r)/255)*1000)/1000;
      var greenVal=Math.round(((hexToRgb(colorInput.value).g)/255)*1000)/1000;
      var blueVal=Math.round(((hexToRgb(colorInput.value).b)/255)*1000)/1000;
      var opacVal=opacInput.value;
      var matrixValues="0 0 0 0 " + redVal + " 0 0 0 0 " + greenVal + " 0 0 0 0 " + blueVal + " 0 0 0 " + opacVal + " 0";
      colMatrixPrim.setAttribute("values", matrixValues);
      
      dispCOLMATRIX.innerHTML=matrixValues;
    };

   function changeOffset(){
     var xOffset= distInput.value * Math.sin(angleInput.value*(Math.PI/180));
     var yOffset= distInput.value * Math.cos(angleInput.value*(Math.PI/180));   
     offsetPrim.setAttribute("dx", xOffset);
     offsetPrim.setAttribute("dy", yOffset);
     dispDX.innerHTML = (Math.round((xOffset*100)))/100;
     dispDY.innerHTML = (Math.round((yOffset*100)))/100;
   };

  function changeShadow(){
    spreadPrim.setAttribute("slope", (spreadInput.value*10)+1);
    sizePrim.setAttribute("stdDeviation", sizeInput.value);
    noisePrim.setAttribute("k1", noiseInput.value);
    noisePrim.setAttribute("k2", 1-noiseInput.value);    
    
    dispSPREAD.innerHTML = Math.round((spreadInput.value*10+1)*100)/100;
    dispSIZE.innerHTML = sizeInput.value;
    dispK1.innerHTML = noiseInput.value;
    dispK2.innerHTML = Math.round((1-noiseInput.value)*100)/100;
  };

function changeContour(contourNum){
   contourPrim.setAttribute("tableValues", contourArrays[contourNum]);
   contourInput[contourNum].setAttribute("fill-opacity", ".01");
   contourInput[activeContour].setAttribute("fill-opacity", ".2");

   dispCONTOUR.innerHTML=contourArrays[contourNum];
  
   activeContour=contourNum;
  };


function hexToRgb(hex) {
    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16)
    } : null;
}


              
            
!
999px

Console