You Don’t Need a
Framework for That

Estelle Weyl

instartlogic.github.io/p/overkill

instart logic

Making web and mobile applications
fast, secure, and easy to operate.

  • JS Streaming
  • HTML Streaming
  • Image Optimization
  • Machine Learning
  • Application Virtualization
  • Intelligent CDN

My First Framework

My old portfolio

The code

var isDHTML, isID, isAll, isLayers;

if (document.getElementById) {
  isID = 1; isDHTML = 1;
} else {
  if (document.all) {
    isAll = 1; isDHTML = 1;
  } else {
    browserVersion = parseInt(navigator.appVersion);
    if ((navigator.appName.indexOf('Netscape') != -1) && (browserVersion == 4)) {
      isLayers = 1; isDHTML = 1;
    }
   }
}

function findDOM(objectID,withStyle) {
 if (withStyle == 1) {
   if (isID) { return (document.getElementById(objectID).style) ; }
   else { 
     if (isAll) { return (document.all[objectID].style); }
     else {
        if (isLayers) { return (document.layers[objectID]); }
     };
   }
 } else {
    if (isID) { return (document.getElementById(objectID)); 
    } else { 
       if (isAll) { 
          return (document.all[objectID]); 
       } else {
            if (isLayers) { return (document.layers[objectID]); }
       };
    }
  }
}

function setClass(objectID,newClass) {
    var dom =findDOM(objectID, 0);
    dom.className = newClass;
}

Frameworks

Original Purpose & Goal

Normalize browser features
Code once, works everywhere

addEventListener and attachEvent

Universally supported since...

addEventListener
IE9
getElementsByClassName()
IE9
Selectors API
IE8. querySelector(), querySelectorAll()
classList
IE 10 / 12. toggle(), add(), remove()
getAttribute()
always supported!

Frameworks are Good

Don't reinvent the wheel

Faster, optimized, readable code

Function chaining & implicit iteration behavior

Less code. Faster to code.

Seriously?

<script src="jquery.js"></script>
          
<script type="text/javascript">                                         
   $('li:first').addClass('first');     
</script>
Photo: Kenneth Lu

Downsides

  • HTML Fundamentals
    • Valid Markup
    • Semantics
    • Elements
    • Attributes
  • Accessibility
  • CSS Fundamentals
    • Inline
    • Selectors
    • Bloat
  • Performance
  • Laziness
Many developers who have grown up only using frameworks have a total lack of understanding about the fundamental of HTML such as valid and semantic markup.

This is of great concern as semantic markup is one of the core principles of an accessible web.

— Russ Weakley, (@russmaxdesign) Front End Frameworks -- are they accessible

Screen Reader experience

click here

Hearing impaired experience

Color Blindness experience

Disability: a mismatch in interaction between the features of a person’s body and the features of the environment in which they live. — Alistair Duggin (@dugboticus) April 14, 2016

We all benefit from the ADA

  • Created by iconsmind.comfrom the Noun Project

Disability is a spectrum

permanent
situational
  • Parapalegic
  • Broken Leg
  • Stillettos
  • Blind
  • Reading Glasses
  • Sun Glare
  • Dyslexic
  • Medicated
  • Distracted
  • Quadrapalegic
  • Broken Arm
  • Holding a Baby
  • Hard of Hearing
  • Aircraft Marshaller
  • Forgotten Headphones
permanent
situational

Accessible Rich Internet Applications

Frameworks enable accessible site creation
but don’t guarantee accessibility.

You need to understand the
output you're generating.

November 2010

In 2010, content was Images=416kb, HTML=34kb, Stylesheets=25kb, Scripts=113kb, Fonts=2kb, and Other=22kb for a total of 702kb

August 2016

In 2016, content is Images=1299kb, HTML=61kb, Stylesheets=67kb, Scripts=421kb, Fonts=73kb, Video=421 and Other=16kb for a total of 2463 kb

2010 vs 2016

351%

Mobile Matters

  • Minimize Battery usage
  • Reduce Latency (fewer HTTP requests)
  • Manage limited memory
  • Ensure a responsive UI
Latency
RDD
The web wins each time a dev chooses to build a web app, no matter the tech, library, or framework they use. But every feature has a cost. Those costs might not be noticeable or important on desktop.

On a low end mobile device on a terrible network, they are huge.

Matthew McNulty (@mattsmcnulty)August 28, 2016

think

Developer Markup

<ul>
  <li>
    <label for="expiration">Credit Card Expiration Month</label>
    <input id="expiration" type="tel" placeholder="MM/YY" class="masked" 
    pattern="(1[0-2]|0[1-9])\/\d\d" data-valid-example="11/18" 
    title="2-digit month and 2-digit year greater than 01/15">
  </li>

<li>
  <label for="zip">Zip Code</label>
  <input id="zip" type="tel" name="zipcode" class="masked" 
  placeholder="XXXXX" pattern="\d{5}" title="5-digit zip code">
</li>
<li>
  <label for="zipca">Canadian Zip Code</label>
  <input id="zipca" type="text" name="zipcodeca"  class="masked"
  placeholder="XXX XXX" pattern="\w\d\w \d\w\d" data-charset="_X_ X_X" 
  title="6-character alphanumeric zip code in the format of A1A 1A1">
</li>
<li>
  <label for="tel">Telephone</label>
  <input id="tel" type="tel" name="phone"  class="masked"
  placeholder="(XXX) XXX-XXXX" pattern="\(\d{3}\) \d{3}\-\d{4}" title="10-digit number">
</li>
<li>
  <label for="cc">Credit Card Number</label>
  <input id="cc" type="tel" name="ccnumber"  class="masked"
  placeholder="XXXX XXXX XXXX XXXX" pattern="\d{4} \d{4} \d{4} \d{4}" title="16-digit number">
</li>
</ul>
Input Masking README.md
<li>
  <label for="zip">Zip Code</label>
  <span class="shell">
    <span aria-hidden="true" id="zipMask"><i></i>XXXXX</span>
    <input id="zip" type="tel" name="zipcode" pattern="\d{5}" 
    class="masked" title="5-digit zip code" maxlength="5" 
    placeholder="XXXXX" aria-label="Zip Code: 5-digit zip code">
  </span>
</li>

on data entry...123XX  123XX

<li>
  <label for="zip">Zip Code</label>
  <span class="shell">
    <span aria-hidden="true" id="zipMask"><i>123</i>XX</span>
    <input id="zip" type="tel" name="zipcode" pattern="\d{5}" 
    class="masked" title="5-digit zip code" maxlength="5" placeholder="XXXXX"
     aria-label="Zip Code: 5-digit zip code">
  </span>
</li>

Create the Mask

  // replaces each masked input t with a shell containing the input and it's mask.
  createShell : function (input) {
    var wrap = document.createElement('span'),
        mask = document.createElement('span'),
        emphasis = document.createElement('i'),
        inputClass = input.getAttribute('class'),
        title = input.getAttribute('title'),
        id = input.getAttribute('id'),
        placeholder = document.createTextNode(input.getAttribute('placeholder'));

    input.setAttribute('maxlength', placeholder.length);
    if(title){
      input.setAttribute('aria-label', document.querySelector("label[for= " + id + "]").innerText + ": " + title);
    }

    mask.setAttribute('aria-hidden', 'true');
    mask.setAttribute('id', id + 'Mask');
    mask.appendChild(emphasis);
    mask.appendChild(placeholder);

    wrap.setAttribute('class', 'shell');
    wrap.appendChild(mask);
    input.parentNode.insertBefore( wrap, input );
    wrap.appendChild(t);
  },

Style the Masking

.shell { position: relative; line-height: 1; }
  .shell span {
    position: absolute; left: 3px; top: 1px;
    color: $themeColor;
    pointer-events: none;
    z-index: -1; }
    .shell span i { /* any of these 3 will work */
      color: transparent;
      opacity: 0;
      visibility: hidden; 
      }

.shell span, input.masked { /* make them match */
  background-color: transparent;
  font-size: 16px; font-family: monospace; padding-right: 10px; text-transform: uppercase; }

/* hide placeholder */
.shell .masked::-webkit-input-placeholder {color: transparent;}
.shell .masked::-moz-placeholder {color: transparent;}
.shell .masked:-ms-input-placeholder {color: transparent;}
.shell .masked::placeholder { color: transparent;}
  

ARIA Accessibilty

  • aria-labeledby="otherElement idValues"
  • aria-label="Read by Screen Reader"
  • <label for="idOfFormControl"> (or implicit label)
  • placeholder
  • title
  • not accessible
<label for="telephone">Telephone Number</label>
  <input type="tel" id="telephone" placeholder="(XXX) XXX-XXXX"
  aria-describedby="hint">
  <span class="hint" id="hint">10-digit phone number</span>
10-digit phone number

Failed example of RDD in Production

https://secure.checkout.visa.com/addressaddnew

Carousel script is 1.1kb
Merry Go Round
Ceci n'est pas un carousel

Merry-go-round

http://github.io/estelle/merry-go-round

Semantic Failure. JS and ARIA compensation.

<section id="footer-listbox" role="listbox" aria-label="Select your country" class="footer-languageSelector">
  <section role="option" tabindex="-1" aria-selected="true" 
    id="footerLanguageOption-0" data-value="AR" class="footer-languageSelector-item">
    <label>Argentina</label>
    <i class="footer-languageSelector-item-icon footer-img-AR"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-1" data-value="AU" class="footer-languageSelector-item">
    <label>Australia</label>
    <i class="footer-languageSelector-item-icon footer-img-AU"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-2" data-value="BR" class="footer-languageSelector-item">
    <label>Brazil</label>
    <i class="footer-languageSelector-item-icon footer-img-BR"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-3" data-value="CA" class="footer-languageSelector-item">
    <label>Canada</label>
    <i class="footer-languageSelector-item-icon footer-img-CA"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-4" data-value="CL" class="footer-languageSelector-item">
    <label>Chile</label>
    <i class="footer-languageSelector-item-icon footer-img-CL"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-5" data-value="CN" class="footer-languageSelector-item">
    <label>China</label>
    <i class="footer-languageSelector-item-icon footer-img-CN"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-6" data-value="CO" class="footer-languageSelector-item">
    <label>Colombia</label>
    <i class="footer-languageSelector-item-icon footer-img-CO"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-7" data-value="HK" class="footer-languageSelector-item">
    <label>Hong Kong</label>
    <i class="footer-languageSelector-item-icon footer-img-HK"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-8" data-value="MY" class="footer-languageSelector-item">
    <label>Malaysia</label>
    <i class="footer-languageSelector-item-icon footer-img-MY"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-9" data-value="MX" class="footer-languageSelector-item">
    <label>Mexico</label>
    <i class="footer-languageSelector-item-icon footer-img-MX"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-10" data-value="NZ" class="footer-languageSelector-item">
    <label>New Zealand</label>
    <i class="footer-languageSelector-item-icon footer-img-NZ"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-11" data-value="PE" class="footer-languageSelector-item">
    <label>Peru</label>
    <i class="footer-languageSelector-item-icon footer-img-PE"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-12" data-value="SG" class="footer-languageSelector-item">
    <label>Singapore</label>
    <i class="footer-languageSelector-item-icon footer-img-SG"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-13" data-value="ZA" class="footer-languageSelector-item">
    <label>South Africa</label>
    <i class="footer-languageSelector-item-icon footer-img-ZA"></i>
  </section>
  <section role="option" tabindex="-1" aria-selected="false"  
    id="footerLanguageOption-14" data-value="AE" class="footer-languageSelector-item">
    <label>United Arab Emirates</label>
    <i class="footer-languageSelector-item-icon footer-img-AE"></i>
  </section>
</section>
5.8kb for the dropkick js file with jquery dependencyof 38.6 kb minified

Semantic: Minimal JS. Accessible by Default.

<fieldset class="languageSelector">
  <legend>Select your country:</legend>
  <ul>
    <li>
        <input type="radio" name="langSelect"  id="langAR" value="AR">
        <label for="langAR" class="langAR">Argentina</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langAU" value="AU">
        <label for="langAU" class="langAU">Australia</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langBR" value="BR">
        <label for="langBR" class="langBR">Brazil</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langCA" value="CA">
        <label for="langCA" class="langCA">Canada</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langCL" value="CL">
        <label for="langCL" class="langCL">Chile</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langCN" value="CN">
        <label for="langCN" class="langCN">China</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langCO" value="CO">
        <label for="langCO" class="langCO">Colombia</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langHK" value="HK">
        <label for="langHK" class="langHK">Hong Kong</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langMY" value="MY">
        <label for="langMY" class="langMY">Malaysia</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langMX" value="MX">
        <label for="langMX" class="langMX">Mexico</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langNZ" value="NZ">
        <label for="langNZ" class="langNZ">New Zealand</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langPE" value="PE">
        <label for="langPE" class="langPE">Peru</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langSG" value="SG">
        <label for="langSG" class="langSG">Singapore</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langZA" value="ZA">
        <label for="langZA" class="langZA">South Africa</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langAE" value="AE">
        <label for="langAE" class="langAE">United Arab Emirates</label>
    </li>
    <li>
      <input type="radio" name="langSelect" id="langUS" value="US">
        <label for="langUS" class="langUS">United States</label>
    </li>
  </ul>
</fieldset>
Selector script is 917 bytes

CSS: Nothing Fancy

footer {
  fieldset {
      width: 215px;
      height: 160px;
      padding-right: 7px;
    li {
      font-size: $small;
      width: 100%;
      padding-left: 5px;
      border-top: 1px solid $label;
      line-height: 34px;
    }
    label {
      color: $white;
      background-position: 95% 50%;
      display: block;
      padding-left: 3px;
    }
  }
}

CSS: Nothing Fancy

footer {
  &.open {
    height: 168px; 
  }
  &.closed fieldset {
    transform: scale(1,0); 
  }
  fieldset {
    input[type=radio], legend {
    opacity: 0.01;
    position: absolute; right: 0px;
  }
    label:active,
    label:focus,
    label:hover,
    :checked + label {
      outline: 1px dotted $white;
      background-color: $mediumLightGray;
    }
  }
}
New.
Shiney.
Resume
Filler.

think

Front End Requirements

  • HTML Fundamentals
    • Valid Markup
    • Semantics
    • Elements
    • Attributes
  • CSS Fundamentals
    • Inline
    • Selectors
    • Cascade
    • Properties / Values
  • JavaScript Fundamentals
  • Progressive Enhancement
  • Accessibility
  • Performance
  • Security
  • User Experience & Design
  • Good Taste
  • Social Skills
  • Communication & Writing
  • Teaching
  • Debate
  • Documentation
  • Jane/Jack of all trades

Questions?

estelle@instartlogic.com
@estellevw / @webdevtips

all talks at instartlogic.github.io