SitePoint Sponsor

User Tag List

Results 1 to 15 of 15
  1. #1
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,114
    Mentioned
    448 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.)
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."

  2. #2
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,890
    Mentioned
    211 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,114
    Mentioned
    448 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.
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."

  4. #4
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,890
    Mentioned
    211 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,114
    Mentioned
    448 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.
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."

  6. #6
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,114
    Mentioned
    448 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.
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."

  7. #7
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,890
    Mentioned
    211 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,114
    Mentioned
    448 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.
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."

  9. #9
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,890
    Mentioned
    211 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,114
    Mentioned
    448 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.
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."

  11. #11
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,890
    Mentioned
    211 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!

  12. #12
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,114
    Mentioned
    448 Post(s)
    Tagged
    8 Thread(s)
    Quote Originally Posted by Pullo View Post
    Hey cool,

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

    Nice one!
    Thanks. I didn't expect it to work, as I did try a few things like that before, which all failed. Thanks to your code, though, I got to have another try. I expected you to say it was inefficient, though.
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."

  13. #13
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,114
    Mentioned
    448 Post(s)
    Tagged
    8 Thread(s)
    Just one thing I wondered. A few variables appear without being declared (is that the right terminology) and I'm sure I've read that it's best to do this first. I've messed around with it a bit:

    Code:
              var el, d = document, bd = d.body, div = d.createElement("div");
    	  function createSpan(b, v){
    	    el = d.createElement("span");
    	    el.setAttribute("tabindex","0");
    	    el.appendChild(d.createTextNode(b));
    	    div.appendChild(el);
    	    
    	    bd.style.fontSize = "100%";
    	    el.onclick = function(){
    	      bd.style.fontSize = parseFloat(bd.style.fontSize) + v + "%";
    	    }
    	    el.onkeypress = el.onclick;
    	  }
    	  
    	  div.setAttribute("class","buttons");
    	  createSpan("Bigger", 10);
    	  createSpan("Smaller", -10);
    	  d.body.appendChild(div);
    Often I see the variable declared (or even redeclared) inside the function where it actually appears. Does it matter where it appears?
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."

  14. #14
    Gre aus'm Pott gold trophysilver trophybronze trophy
    Pullo's Avatar
    Join Date
    Jun 2007
    Location
    Germany
    Posts
    5,890
    Mentioned
    211 Post(s)
    Tagged
    12 Thread(s)
    Hi Raplh,

    Quote Originally Posted by ralph.m View Post
    Just one thing I wondered. A few variables appear without being declared (is that the right terminology)
    Yup, it is the correct terminology.

    Quote Originally Posted by ralph.m View Post
    and I'm sure I've read that it's best to do this first.
    Often I see the variable declared (or even redeclared) inside the function where it actually appears. Does it matter where it appears?
    This is all a question of scope (and my bad programming style ).
    A small example:

    Code JavaScript:
    var g = "global";
    function go() { 
     var l = "local";
    }
    console.log(g);
    go();
    console.log(l);

    outputs:

    Code:
    global
    Uncaught ReferenceError: l is not defined
    Using var limits the variable l to the current scope, i.e. that of the function go().

    However, if we omit var:

    Code JavaScript:
    var g = "global";
    function go() { 
     l = "local";
    }
    console.log(g);
    go();
    console.log(l);

    outputs:

    Code:
    global
    local
    This is because the variable bubbles up through the layers of scope until it encounters a variable by the given name or the global object (window, if you are doing it in the browser), where it then attaches.

    To come back to your question:
    It is good practice to declare variables with var before using them (shame on me).
    It also matters where you declare them (as we saw above), as the scope of variables declared using var within a function are limited to that function.

    Here's the most recent iteration of your code, revised:

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

    You might also find the following interesting:

    Smashing Magazine - What You Need To Know About JavaScript Scope
    StackOverflow - JavaScript Variable Scope
    StackOverflow - Javascript: is using 'var' to declare variables optional?

  15. #15
    It's all Geek to me silver trophybronze trophy
    ralph.m's Avatar
    Join Date
    Mar 2009
    Location
    Melbourne, AU
    Posts
    24,114
    Mentioned
    448 Post(s)
    Tagged
    8 Thread(s)
    Thanks @Pullo

    I have read about scope, but it goes in one ear and out t'other until I need to know. At least I remembered the recommendation to use var, though I couldn't remember why. Thanks for the very clear examples and explanation. (Better than in the books. )

    Thanks for the links, too.

    I still find it funny how you can declare variables after you see them in a function, but I guess the browser reads those declarations before the function is actually invoked (if that's the right word), so I guess I'm getting the conepts slowly. On more complex scripts, I get quite befuddled about the order of everything and what calls what is which order ... Still dunno how people write that stuff!
    Facebook | Google+ | Twitter | Web Design Tips | Free Contact Form

    Forum Usage: Tips on posting code samples, images and more

    Forrest Gump: "IE is like a box of chocolates: you never know what you're gonna get."


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
  •