SitePoint Sponsor

User Tag List

Results 1 to 15 of 15

Hybrid View

  1. #1
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,331
    Mentioned
    463 Post(s)
    Tagged
    8 Thread(s)

    Refining a Text Resize script

    I was interested in writing a small script that can offer buttons for increasing and decreasing text size. This is just a learning exercise (I'm a noob). I Googled scripts for this, but all of them were obtrusive. I'd like to make this unobtrusive, but also as efficient as possible. I've modified this script to make it unobtrusive, and it works, but I suspect this could be done a lot better.

    Code:
    <!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>TextResize</title>
    	
    <style media="all">
    body {font: 100% serif;}
    .buttons span {display: inline-block; padding: 20px; background: #f7f7f7; cursor:pointer}
    .buttons span:hover {background: orange;}
    .buttons span:focus {background: green; outline: none;}
    </style>
    </head>
    <body>
    
    <p>This is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text</p>
    
    <script>
    var d = document;
    var div = d.createElement("div");
    div.setAttribute("class","buttons");
    var spanBig = d.createElement("span");
    spanBig.setAttribute("tabindex","0");
    var bigText = d.createTextNode("Bigger");
    spanBig.appendChild(bigText);
    var spanSmall = d.createElement("span");
    spanSmall.setAttribute("tabindex","0");
    var smallText = d.createTextNode("Smaller");
    spanSmall.appendChild(smallText);
    div.appendChild(spanBig);
    div.appendChild(spanSmall);
    d.body.appendChild(div);
    
    spanBig.onclick = function() {
    	resizeText(10);
    }
    
    spanSmall.onclick = function() {
    	resizeText(-10);
    }
    
    function resizeText(multiplier) {
        if (d.body.style.fontSize == "") {
            d.body.style.fontSize = "100%";
        }
        d.body.style.fontSize = parseFloat(d.body.style.fontSize) + multiplier + "%";
    }
    
    spanBig.onkeypress = spanBig.onclick;
    spanSmall.onkeypress = spanSmall.onclick;
    </script>
    
    </body></html>
    Does anyone have any suggestions on how to tighten this up a bit? I really dislike having the two .onclick references. (I added a few extra bits to make it keyboard accessible, too, which is another requirement. I'd also love it if the natural browser resizing would still work, too—i.e. Command + 0 to reset the page. Hate the way JS disables normal browser bahavior—but then, I like to keep my cake and eat it too.)

  2. #2
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    6,086
    Mentioned
    219 Post(s)
    Tagged
    12 Thread(s)
    Hi Ralph,

    Quote Originally Posted by ralph.m View Post
    I really dislike having the two .onclick references.
    I'm on the hop right now, but just wanted to post this suggestion.
    What you could do, is add a class to the span elements you want to target.
    Then you could select all of the elements with this class, loop through them and reference the individual elements within the loop using this.
    You could a data-attribute to the span elements as you create them, so that you know which argument to pass to the resizeText function.

    I'll have a closer look at your code when I'm back at the PC and see if I can help you out more.

  3. #3
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,331
    Mentioned
    463 Post(s)
    Tagged
    8 Thread(s)
    Quote Originally Posted by Pullo View Post
    select all of the elements with this class, loop through them and reference the individual elements within the loop using this.
    I did play around with that, but got all messed up. Not really able to think in JS yet, other than "cat on mat" kind of stuff. Keen to learn, though.

    You could a data-attribute to the span elements as you create them, so that you know which argument to pass to the resizeText function.
    Ah, that sounds interesting. I'd love to see that in action.

    I'll have a closer look at your code when I'm back at the PC and see if I can help you out more.
    Many thanks. That would be great. I've seen this kind of functionality so many times over the years, I'm surprised I didn't stumble across an unobtrusive version. There are jQuery versions, of course, but I'd much rather learn JS without a library at this stage. And I'd really like to have the minimum code needed to do this.

  4. #4
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    6,086
    Mentioned
    219 Post(s)
    Tagged
    12 Thread(s)
    Hi Ralph,

    I had a look at the script and have one major suggestion about what could be improved:

    The main thing I try and avoid when writing JS is repetition (as you mentioned yourself).
    In your version you create an element, do a bunch of stuff with it then create another element and do exactly the same stuff with it.
    This isn't so tragic for two elements, but would suck if you had to do it for two hundred.

    So, my recommendation would be to stick all of this into a function.
    Here's your revised script:

    Code:
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8">
        <title>TextResize</title>
        <style media="all">
          body {font: 100% serif;}
          .buttons span {display: inline-block; padding: 20px; background: #f7f7f7; cursor:pointer}
          .buttons span:hover {background: orange;}
          .buttons span:focus {background: green; outline: none;}
        </style>
      </head>
      
      <body>
        <p>This is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text this is text</p>
        
        <script>
          function resizeText(multiplier) {
            if (d.body.style.fontSize == "") {
              d.body.style.fontSize = "100%";
            }
            d.body.style.fontSize = parseFloat(d.body.style.fontSize) + multiplier + "%";
          }
          
          function createSpan(b, v){
            el = d.createElement("span");
            el.setAttribute("tabindex","0");
            t = d.createTextNode(b);
            el.appendChild(t);
            div.appendChild(el);
            el.onclick = function(){
              resizeText(v);
            }
            el.onkeypress = el.onclick;
          }
          
          var d = document;
          var div = d.createElement("div");
          div.setAttribute("class","buttons");
          createSpan("Bigger", 10);
          createSpan("Smaller", -10);
          d.body.appendChild(div);
        </script>
      </body>
    </html>
    As you can see I have created a function called createSpan which takes two arguments:
    1. The text for the element
    2. The size by which the text should be decresed on click.

    I've also used shorter variable names, as they are basically used, then thrown away and don't pop up else where in the code.
    This is just a personal preference.

    This is by no means a definitive answer, so I would be glad to hear anyone else's input on this.

    Hope that helps.

  5. #5
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,331
    Mentioned
    463 Post(s)
    Tagged
    8 Thread(s)
    Ooh, thanks so much, "Dave". That looks great—much more efficient. Exactly the sort of thing I was after. And I do like the shorter var names, too.

    I'm going to pore over this and will let you know if I don't understand any of it. It certainly makes a big difference to have a go first and then see a better way.

  6. #6
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,331
    Mentioned
    463 Post(s)
    Tagged
    8 Thread(s)
    I was looking at tightening up the first function, too. Still wondering if it can be done differently (it was just something I found on the web). I can see why you can't just say

    Code:
    d.body.style.fontSize = "100%";
    without the if, but was trying something like a += to keep incrememting it or something, but got nowhere with that.

    Anyhow, just for fun, I screwed it down to this at least:

    Code:
    function resizeText(m) {
          var b = d.body;
            if (b.style.fontSize == "") {
              b.style.fontSize = "100%";
            }
            b.style.fontSize = parseFloat(b.style.fontSize) + m + "%";
          }
    Wondering if something similar can be done with .style.fontSize.

  7. #7
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    6,086
    Mentioned
    219 Post(s)
    Tagged
    12 Thread(s)
    You could omit the function entirely.

    Code:
    <script>
      function createSpan(b, v){
        el = d.createElement("span");
        el.setAttribute("tabindex","0");
        t = d.createTextNode(b);
        el.appendChild(t);
        div.appendChild(el);
        el.onclick = function(){
          d.body.style.fontSize = (d.body.style.fontSize == "")? "110%" : parseFloat(d.body.style.fontSize) + v + "%";
        }
        el.onkeypress = el.onclick;
      }
      
      var d = document;
      var div = d.createElement("div");
      div.setAttribute("class","buttons");
      createSpan("Bigger", 10);
      createSpan("Smaller", -10);
      d.body.appendChild(div);
    </script>

  8. #8
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,331
    Mentioned
    463 Post(s)
    Tagged
    8 Thread(s)
    That's nice. Although, the initial 110% seems initially to make Smaller increase the text size if it's clicked first.

  9. #9
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    6,086
    Mentioned
    219 Post(s)
    Tagged
    12 Thread(s)
    Really?
    Not for me.

    Your initial function checks if the body tag has a font-size style.
    If not, it applies one of 100%, then increases it by 10%.

    Could it be a MAC thing?

  10. #10
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,331
    Mentioned
    463 Post(s)
    Tagged
    8 Thread(s)
    Quote Originally Posted by Pullo View Post
    Really?
    Not for me.
    Hm, that's odd. If the first thing I click with your revised code (post #7) is the Smaller button, the text initially resizes, then everything proceeds as normal. Would be odd if just a Mac thing, but happens in all the Mac browsers. (Seems to make sense, though: if there's not a font size set, which is the case on the first click, everything goes to 110%, even if the Smaller button is clicked. Is that the right way to read the ternary operation?)

    Anyhow, I also tried this, which is not as efficient, but seems to work OK:

    Code:
    <script>
      function createSpan(b, v){
        el = d.createElement("span");
        el.setAttribute("tabindex","0");
        t = d.createTextNode(b);
        el.appendChild(t);
        div.appendChild(el);
        var b = d.body;
        b.style.fontSize = "100%";
        el.onclick = function(){
          b.style.fontSize = parseFloat(b.style.fontSize) + v + "%";
        }
        el.onkeypress = el.onclick;
      }
      
      var d = document;
      var div = d.createElement("div");
      div.setAttribute("class","buttons");
      createSpan("Bigger", 10);
      createSpan("Smaller", -10);
      d.body.appendChild(div);
    </script>
    I'm just playing around now, but this is fascinating. Hard to do it without a guiding hand, though. I'm really loving your createSpan() function.

  11. #11
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    6,086
    Mentioned
    219 Post(s)
    Tagged
    12 Thread(s)
    Hey cool,

    I like that more than my suggestion as ternary conditionals are always confusing to read.

    Nice one!


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •