1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Function works with inline CSS only

Discussion in 'JavaScript' started by Tony Brar, Jul 14, 2013.

  1. #1
    Hi Digital Point,

    I'm writing a content sliding function without the use of jQuery or any other JS library.
    I don't want to discuss the reasons or start WW3 over this, but I'm not using jQuery because it requires including another file for the user (yes I know about caching) and I don't want to use many of it's functions anyway.
    The latest working version of my content slider requires that the height of your element is specified with inline CSS.
    Here it is, working at least in latest version of Chrome:
    And here is the same JS but with ALL CSS in the <style> tag.
    Can anyone explain how to fix this or at least let me know why this is happening?

    Tony Brar, Jul 14, 2013 IP
  2. xtmx

    xtmx Active Member

    Likes Received:
    Best Answers:
    Trophy Points:
    Add the following at the beginning of the function:

    Code (Text):
    1. if(!element.style.height) {
    2.  var s = getComputedStyle(element);
    3.  element.style.height = s.getPropertyValue('height');
    4. }
    You can use a currentStyle fallback for MSIE, if you'd like.
    xtmx, Jul 14, 2013 IP
  3. Tony Brar

    Tony Brar Active Member

    Likes Received:
    Best Answers:
    Trophy Points:
    What version(s) of IE would require currentStyle?

    Tony Brar, Jul 14, 2013 IP
  4. xtmx

    xtmx Active Member

    Likes Received:
    Best Answers:
    Trophy Points:
    I did a quick IETester test, and it appears that getComputedStyle works in IE9+.

    Hate to admit it, but I actually prefer currentStyle to getComputedStyle, and wish more browsers supported it. This is a fallback for IE8- (it works in any MSIE browser):

    Code (Text):
    1. element.style.height = element.currentStyle.height;
    So the full beginning code would be:

    Code (Text):
    1. if(!element.style.height) {
    2. var s;
    3. try {
    4.   s = getComputedStyle(element).getPropertyValue('height');
    5. } catch(msie) {
    6.   s = element.currentStyle.height;
    7. }
    8. element.style.height = s;
    9. }
    xtmx, Jul 14, 2013 IP
  5. Tony Brar

    Tony Brar Active Member

    Likes Received:
    Best Answers:
    Trophy Points:
    Thanks a lot!
    My website won't be live until IE 11 or 12 so I don't need to worry about compatibility.
    If you don't mind I'd just like to know why you prefer currentStyle over getComputedStyle (it might be useful to know).

    Tony Brar, Jul 14, 2013 IP
  6. deathshadow

    deathshadow Prominent Member

    Likes Received:
    Best Answers:
    Trophy Points:
    There are a number of issues with your approach that really should be addressed. One of the biggest is the COMPLETE lack of graceful degradation scripting off. Any good script to do this should leave all the items expanded when scripting is unavailable given how many users disable it on purpose. (see Opera users, all the people who have downloaded the noScript plugins for FF and Chrome...)

    Good rule of thumb, if you can't make the page work without scripting, you probably shouldn't be throwing scripting at it.

    Rather than playing with computed style, I'd use the script to add a extra DIV around the parent DIV, using the heading as the script's target. You could then use offsetHeight on the existing DIV to set the height of the outer DIV, or the height of the heading since it could be targeted. I would NOT use the onclick attribute in the markup, as good scripting really shouldn't be in the markup to begin with. (I personally feel that all the 'on___' attributes should be made obsolete and removed from the specification). Even better, since we can just set the height on an outer element, we can use overflow:hidden to much better effect along with CSS3 transitions. Old browsers it will pop open instantly, modern browsers (and IE 10) will get the animation.

    So for example if you had this markup:
    Code (Text):
    1. <div class="content">
    2.     <h2 id="demoNotice">No JQ, CSS does the hard stuff</h2>
    3.     <p>
    4.         jQuery? We don't need no steenking jQuery!!! Just more proof what pointless bloat that idiotic BS library really is.
    5.     </p><p>
    6.         Unlike a lot of other attempts, this gracefully degrades scripting off since the outer wrapper used to constrain these sections is applied by the script.
    7.     </p>
    8. </div>
    You could use this script:
    Code (Text):
    1. function showHide(targets) {
    3.     var
    4.         d = document;
    6.     function addShowHide(targetId) {
    8.         if (control = d.getElementById(targetId)) {
    9.             var
    10.                 newDiv = d.createElement('div'),
    11.                 newSpan = d.createElement('span'),
    12.                 p = control.parentNode;
    14.             newDiv.className = 'showHide';
    15.             p.parentNode.replaceChild(newDiv,p);
    16.             newDiv.appendChild(p);
    17.             newDiv.style.height = control.clientHeight + 'px';
    18.             newSpan.appendChild(d.createTextNode('+'));
    19.             newSpan.className = 'showHideControl';
    20.             control.shrunk = true;
    21.             control.insertBefore(newSpan,control.firstChild);
    23.             control.onclick = function(e) {
    24.                 e = e || window.event;
    25.                 var t = e.target || e.srcElement;
    26.                 if (t.className == 'showHideControl') t = t.parentNode;
    27.                 t.shrunk = !t.shrunk;
    28.                 t.parentNode.parentNode.style.height = (
    29.                     t.shrunk ?
    30.                     t.clientHeight :
    31.                     t.parentNode.offsetHeight
    32.                 ) + 'px';
    33.                 t.firstChild.replaceChild(
    34.                     d.createTextNode(t.shrunk ? '+' : '-'),
    35.                     t.firstChild.firstChild
    36.                 );
    37.                 e.stopPropagation? e.stopPropagation() : e.cancelBubble = true;
    38.             }
    40.         }
    41.     }
    43.     if (targets instanceof Array) {
    44.         for (var t=0; t<targets.length; t++) addShowHide(targets[t]);
    45.     } else addShowHide(targets);
    47. }
    To set it's states cleanly. (should work cross browser back to at least IE7, may even work in 6 though I've not tested it). The CSS for that:

    Code (Text):
    1. .showHide {
    2.     overflow:hidden;
    3.     margin:0 1em 1em;
    4.     border:2px solid #000;
    5.     -webkit-transition:height 0.5s linear;
    6.     transition:height 0.5s linear;
    7. }
    9. .content {
    10.     background:#FFF;
    11. }
    13. h1 {
    14.     font:bold 200%/120% arial,helvetica,sans-serif;
    15.     padding:0.5em;
    16. }
    18. h2 {
    19.     zoom:1; /* trip haslayout, fix IE 7- bugs */
    20.     font:bold 125%/120% arial,helvetica,sans-serif;
    21.     padding:0.4em;
    22.     margin-bottom:0.4em;
    23.     color:#FFF;
    24.     background:#04C;
    25.     border-bottom:2px solid #000;
    26. }
    28. p {
    29.     padding:0 0.5em 1em;
    30. }
    32. .showHideControl {
    33.     display:inline-block;
    34.     overflow:hidden;
    35.     vertical-align:middle;
    36.     font:bold 80%/100% arial,helvetica,sans-serif;
    37.     height:1em;
    38.     width:1em;
    39.     margin-right:0.4em;
    40.     text-align:center;
    41.     color:#000;
    42.     background:#FFF;
    43.     border:2px solid #000;
    44.     border-radius:6px;
    45.     -webkit-box-shadow:inset 0 0 0.3em 0.1em #DEF;
    46.     box-shadow:inset 0 0 0.3em 0.1em #DEF;
    47. }
    Adds a nice styled button. Notice I swap out the button's contents on the fly to indicate the state.

    In a production copy, I'd call it thus just before </body> in the markup:
    Code (Text):
    1. <script type="text/javascript" src="showHide.js"></script>
    2. <script type="text/javascript"><!--
    3.     showHide(['demoNotice','demoLoremIpsum']);
    4. --></script>
    But for now I tossed a working example up on jsfiddle here:

    You'll notice I use clientHeight for the header and offsetHeight for it's parent DIV -- clientHeight doesn't include borders, which is good since we don't want to leave that dividing bottom border showing. Far cleaner and compatible than trying to play with computedStyle, which can do funky things if you accidentally interrupt your animation mid-animate. Likewise the CSS3 transition handles the real grunt-work of opening and closing for you.

    ... and because it's built on the DOM it doesn't force a complete reflow adding the scripting only elements. Again I add the outer DIV and the button/indicator from the scripting, as there is no good reason to have them present when scripting is off.

    The function can take either an array of ID's to target, or a single ID string, and can be called multiple times safely if so desired.

    Hope this helps, or at least gets you thinking different ways of handling this.
    deathshadow, Jul 18, 2013 IP