Monday, 27 October 2014

Lists, pseudo-elements, Chrome and jQuery

I recently worked on a project where I needed to find a way of displaying an ordered list with customised numbers. When clicked, each list item would display a different image on the page and any other images would then be hidden. The list item would also then have an "active" state i.e. the text would display in a different colour and the list number would also display with a different colour. I didn't want to use background images with numbers for the ordered list items as we didn't know how many would be displayed at any one time, so this would not be a scalable solution.

I used this tutorial by Treehouse as a basis for how to display my customised ordered list - I won't go into detail about how to do this here. However I will point out that instead of using the ::before pseudo-element, I used :before to allow support for IE8.

I am writing this post to explain how I got around some of the issues I encountered. Note some elements in the code (such as class and variable names) are ficticious.

My markup looked something like this:
<ol class="list-container">
  <li>Lorem ipsum 1</li>
  <p>Paragraph ipsum 1</p> 
  <li>Lorem ipsum 2</li>
  <p>Paragraph ipsum 2</p> 
  <li>Lorem ipsum 3</li>
  <p>Paragraph ipsum 3</p>
  <li>Lorem ipsum 4</li>
  <p>Paragraph ipsum 4</p> 
</ol>
<div class="image-container">
  <ul>
    <li><img src="images/image1.png" alt=""/></li>
    <li><img src="images/image2.png" alt=""/></li>
    <li><img src="images/image3.png" alt=""/></li>
    <li><img src="images/image4.png" alt=""/></li> 
  </ul>
</div>

and my SCSS looked something like this:
.list-container {
    list-style-type: none;
    list-style-position: outside;
    counter-reset: li;

    li {
     ...
      &:before {
          position: absolute;
          top: -5px;
          left: -2em;
          width: 2em;
          display: block;
          margin: 0 10px 0 0;
          font-size: 110%;
          line-height: 44px;
          color: white; //set colour of ordered list number to white
          text-align: center;
          content: counter(li);
          counter-increment: li;
          @extend .sprites-list-bg-yellow; //use compass to generate sprites
      }
      &.active {
        &:before {
          @extend .sprites-list-bg-blue; //use compass to generate sprites
        }
       ... 
     }
Using a small amount of jQuery, I added some slide transitions for when the list items were clicked.
My jQuery looked something like this:
(function($) {
  $(document).ready(function() { 
var $myList = $('.list-container li');
var $myImage = $('.image-container li'); 
// Show first list item and first paragraph as active on page load.
    $myList.first().addClass('active').next('p').show();
    // When any list item is clicked...
    $myList.click(function() {
      var $thisPos = $(this).parent().children('li').index($(this));
      if (!$(this).hasClass('active')) {
        // ...hide any list item with class "active".
        $myList.removeClass('active').next('p').slideUp('fast');
        // ...and slide down the paragraph under the clicked list item.
        $(this).addClass('active').next('p').slideDown('fast');
        // Show the corresponding image.
        $myImage.hide().eq($thisPos).show();
      }
    });  
})(jQuery);
This pretty much met the design. However, when I tested (in IE8, IE9, Chrome, Firefox and Safari), I found that a couple of browsers weren't playing ball.

Chrome and IE8 both had trouble displaying the list once any of the items had been clicked on. In IE8 the list items seemed to slide on top of each other (almost like they needed a clear: both or something like that) and in Chrome the numbers in the :before looked like they were being sliced in two. Safari and Firefox were fine (of course).
I searched online and immediately found myself reading post-upon-post about jQuery and Chrome and artifacts on the screen.


After quite a bit of head-scratching I decided to refactor my SCSS in the :before pseudo-element. I commented out all of the properties and added them back one by one, to see what would happen. I started with the "position" attribute - when I changed its value to "relative" the list items moved out of alignment relative to their :before elements BUT when I clicked on them, I could see straight away in Chrome that the slicing bug was no longer happening. So I continued refactoring and debugging, and found that setting position to "absolute" indeed was the root of the problem. Switching it to "relative" also solved the IE8 issue where the list items were sliding on top of each other.

My finished SCSS for the :before element turned out to be something like:
&:before {
  position: relative;
  top: 1.3em;
  left: -2.4em;
  width: 2em;
  display: block;
  margin: 0 10px 0 0;
  font-size: 110%;
  line-height: 44px;
  color: white; //set colour of ordered list number to white
  text-align: center;
  content: counter(li);
  counter-increment: li;
  @extend .sprites-list-bg-yellow; //use compass to generate sprites
}
So the lesson here is, as always, test whatever you build. Even modern browsers such as Chrome could possibly have issues displaying simple functions performed by a modern library such as jQuery.

Tweet me (@theonico85) with your thoughts - don't forget to use #webdevgeekout!

Wednesday, 1 October 2014

Learning JavaScript, localStorage, JSON, etc...

At the beginning of this year I decided to focus on improving my JavaScript knowledge. I used a combination of online resources (www.codecademy.com) and books (Professional Javascript for Web Developers by Nicholas C. Zakas) to help get a good grounding of the fundamental concepts and then I built a mini-JS Quiz application (https://github.com/theonicolaou/jsQuiz) with my new-found skills.

As you can see in the README, I have a roadmap for the JS Quiz - my learning experience is far from over! I recently started to look at two of the items in the roadmap at a very basic level - add login functionality using localStorage, and store the quiz questions in a JSON file - to get a better understanding of what might be involved when I eventually get round to continuing the project. This is a short blog post about my experiences of prototyping with JavaScript, JSON and localStorage.

I know the internet is a big place and I know you have to persevere when searching for information/resources/tutorials etc, but I was quite frustrated at how few basic (working) tutorials I found for using localStorage and using JSON with JavaScript. Maybe I wasn't looking in the right places, but I was looking for a long time; I'm sure I spent a good couple of hours trying to find a simple, clear tutorial of how to hook up a JSON file into a JavaScript file and a similar amount of time looking for a tutorial on how to use localStorage. In the end, I found the very basic information I needed (combined with Nicholas Zakas' book) and I created two Plunkr's which I converted into GitHub repos:

Basic HTML5 localStorage example
Type a username and password into the fields and click "Log in" to display the data in an alert. The data is stored at this point. Then you can retrieve it by clicking "Show Data".
To test that localStorage is working, remove the localStorage.setItem lines in the script.js code, then fill in the fields and click "Log in". The alert will display the inputted values but clicking the "Show Data" button will display "null" because by removing localStorage.setItem the values are not being stored. Therefore the "Show Data" button will not have anything to show.

Basic JS with JSON example

A basic example of how to use an external JSON file in JavaScript, by calling it with AJAX. The AJAX looks for a JSON file to parse as long as the onreadystatechange event detects a readyState of 4 (request finished and response is ready) and a status of 200 ("OK"). The JSON file itself is just a collection of name/value pairs, and an array with name/value pairs. The JavaScript then looks for specific values in the JSON file and writes it out into the document.

Both examples are very basic and raw; I know there are elements of the code which can be improved but my main goal was to gain an understanding of how JSON and localStorage works. I think I have achieved my goal and I plan to use my prototypes as a starting point for improving my JS Quiz.

I hope my examples are helpful! Feel free to fork the repos and submit pull requests with improvements!




Sunday, 28 September 2014

"Agile is for life, not just for...projects...?"

Okay, it doesn't have quite the same ring to it, but stay with me here - it actually works! I'm using Agile/Kan-ban in my day-to-day life and it definately works. I wanted to write a short post about it so you can see how it is having a positive impact on my life - and perhaps it will for you too.

In March this year I finally got onto the property ladder when I bought my own place. The decorating/moving-in process was fun and exhausting, but the key was...Agile.

I made a huge spreadsheet of everything that I needed to do in the run-up to my move date in mid-May, which I divided into tasks per week, and I used the Clear app to keep track of everything for a specific week. I also found myself adding unrelated tasks into a separate "To Be Assigned" list in Clear, which I then revisited and added to the weekly lists as I saw fit. Once the week was over, I would move any other tasks back into the "To Be Assigned" list, or into the weekly list for the new week.

This, combined with the advice in David Allen's book "Getting Things Done", really helped me to keep on top of everything. It sounds so simple but it really did work.

Now that I have moved in to my new place I am using Clear pretty much every day. But, more to the point, I am using Agile pretty much every day. If I have something on my mind I make the effort to define everything I can think of which needs to be done, so that I can free my mind and get on with my day. Then, I look at my list (scrum board, or whatever) and prioritise the tasks I need to complete. It might sound geeky, or silly, but just try it and you will never look back!

"Hello World" etc...

So, here we go: my first #webdevgeekout blog post!

I'll be (probably, hopefully) writing about web development-related views and experiences - and I hope you will enjoy reading them!

Stay tuned...