Search code examples
jquerysliderrangeslidervariable-fonts

Font-variation-settings Sliderbar only returning :normal


I am trying to make slider bars that will change the font-variation-settings of a variable font. I am trying to get these sliders to appear dynamically using PHP so that limits my options a tiny bit.

I've edited the post to remove the PHP.

I have the <h1> tag

<h1 class="variableFont" contenteditable="true" >Some Text Here</h1>

I'm using PHP that checks if it's a variable font and then checks which axis the font has then adds the appropriate sliders.

<p>Weight500</p>
<input type="range" min="0" max="1000" value="500" oninput="updatewght(this.value)">

<script>
     function updatewght(newVal){
     
          // Get the current value of font-variation-settings
          var currentSettings = $('.variableFont').css('font-variation-settings');
 
          // Split the current value into an array of variations
          var currentVariations = currentSettings.split(',');

          // Loop through the variations and change the current value
          for (var i = 0; i < currentVariations.length; i++) {
               if (currentVariations[i].indexOf('wght') >= 0) {
                    currentVariations[i] = "'wght' newVal"; // Change the axis value to whatever
               }
          }

          // Join the variations back into a string and set the new value for font-variation-settings
          var newSettings = currentVariations.join(',');
          $('.variableFont').css('font-variation-settings', newSettings);
     }                         

</script>   

The sliders show up like they should, however when I move them it only ever returns

style="font-variation-settings: normal;"

I think the issue lies in where it splits the font-variation-settings and tries to jam it back together, but I can't figure out where I went wrong.


Solution

  • The main problem in your script - the css font-variation-settings property value is empty unless you set some default values.

    var currentSettings = $('.variableFont').css('font-variation-settings');

    You would get different vallues if your text element had some initial values like e.g

    .variableFont{ 
        font-variation-settings: "wdth" 100, "wght" 400
    } 
    

    function updatewght(newVal) {
      // Get the current value of font-variation-settings
      var currentSettings = $(".variableFont").css("font-variation-settings");
    
      // Split the current value into an array of variations
      var currentVariations = currentSettings.split(",");
    
      // Loop through the variations and change the current value
      for (var i = 0; i < currentVariations.length; i++) {
        if (currentVariations[i].indexOf("wght") >= 0) {
          currentVariations[i] = `"wght" ${newVal}`; // Change the axis value to whatever
        }
      }
    
      // Join the variations back into a string and set the new value for font-variation-settings
      var newSettings = currentVariations.join(",");
      $(".variableFont").css("font-variation-settings", newSettings);
    }
    /* latin */
    
    @font-face {
      font-family: 'Open Sans';
      font-style: normal;
      font-weight: 300 800;
      font-stretch: 75% 100%;
      src: url(https://fonts.gstatic.com/s/opensans/v34/mem8YaGs126MiZpBA-UFVZ0b.woff2) format('woff2');
    }
    
    body {
      font-family: 'Open Sans';
      font-size: 3em;
    }
    
    .variableFont {
      font-variation-settings: "wdth" 75, "wght" 300
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <p class="variableFont">Weight500</p>
    <input type="range" data-axis="wght" min="300" max="800" value="300" oninput="updatewght(this.value)">

    Another approach: add data attributes to your sliders to specify the current axis name.

    This way you need only only initializing function looping through all range sliders to update the new variation settings.

    let vfGroups = document.querySelectorAll(".vf-group");
    
    vfGroups.forEach((group) => {
      let textEl = group.querySelector(".preview");
      let axesRangeSliders = group.querySelectorAll("[data-axis]");
      initVariationSliders(axesRangeSliders, textEl);
    });
    
    
    function initVariationSliders(sliders, targetEl) {
      // collect all variations in object
      let variationObj = {};
      sliders.forEach((slider, i) => {
        // apply variation setting
        if (i === sliders.length - 1) {
          updateVariations(slider, targetEl, variationObj);
        }
    
        // attach event handler
        slider.addEventListener("input", (e) => {
          updateVariations(e.currentTarget, targetEl, variationObj);
        });
      });
    
      function updateVariations(slider, targetEl, variationObj) {
        // get axes and values of current element
        let value = slider.value;
        let axis = slider.dataset.axis;
        variationObj[axis] = value;
    
        // convert object to array
        let variation = Object.keys(variationObj).map((key) =>
          [`"${key}"`, +variationObj[key]].join(" ")
        );
        targetEl.style["font-variation-settings"] = variation.join(",");
      }
    }
    /* latin */
    @font-face {
      font-family: 'Open Sans';
      font-style: normal;
      font-weight: 300 800;
      font-stretch: 75% 100%;
      src: url(https://fonts.gstatic.com/s/opensans/v34/mem8YaGs126MiZpBA-UFVZ0b.woff2) format('woff2');
    
    }
    
    @font-face {
      font-family: 'Advent Pro';
      font-style: normal;
      font-weight: 100 900;
      font-stretch: 100% 200%;
      src: url(https://fonts.gstatic.com/s/adventpro/v20/V8mAoQfxVT4Dvddr_yOwhTqtKA.woff2) format('woff2');
      unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
    }
    
    
    
    .preview{
      font-size: 3em;
    }
    
    p{
      margin:0;
    }
    
    .open-sans{
        font-family:'Open Sans';
    }
    
    .advent-pro{
        font-family:'Advent Pro';
    }
    
    .variableFont{
    }
    <div class="vf-group open-sans">
      <p class="preview">Open Sans</p>
      wght: <input type="range" data-axis="wght" min="300" max="800" value="300">
      wdth: <input type="range" data-axis="wdth" min="75" max="100" value="75">
    </div>
    
    
    <div class="vf-group advent-pro">
      <p class="preview">Advent Pro</p>
      wght: <input type="range" data-axis="wght" min="100" max="900" value="300">
       wdth: <input type="range" data-axis="wdth" min="100" max="200" value="100">
    </div>