CSS Disambiguation with WinJS and SPA by ThinqLinq

CSS Disambiguation with WinJS and SPA

Recently, I’ve been working to build with some HTML/JS applications for Windows 8. While I could have built them using XAML/VB-C#, I decided to push myself out of my comfort zone to see what I could do with my web experience in these new Windows Store Apps. In addition, I have a number of customers who are looking to minimize code re-writing by leveraging their existing web assets for these native applications, so I figured I might as well dig into them a bit.

I’m used to the standard page per request model and AJAX based models, but the Windows-8 implementation follows more along the lines of the Single Page Application (SPA) model. As a result, some things become easier (like state management across pages) while others become more tricky (make sure to avoid the global namespace as more JavaScript will stay alive in your apps now).

One of the first Issues I came up against was an issue when navigating between pages and finding that styles that are being applied in child pages are sticking when navigating back to the parent page. I’m sure I’m not alone as this Stack Overflow post indicates.This wouldn’t be an issue in a standard web implementation because the page would be re-loaded along with only the styles that page requested. However, in the Windows Store App model, each page that is loaded will bring it’s associated css and js into scope the first time the page is loaded and be retained as we navigate to other pages. Let’s take a look at an example app to see how this works.

Let’s start by creating a new JavaScript app using the Navigation App template. This will create a solution framework with a default.html page that loads a home.html page into a div called “contenthost”

image

To keep this sample as simple as possible, I’m just going to add one more page to the default template. To do this, create a new folder in the pages folder in the Solution Explorer. I’ll call this folder Detail. In the Detail folder, add a new Page using the Page Control template and call it DetailPage.html.

image

The Page Control template will generate three files in our folder – DetailPage.html, DetailPage.js and DetailPage.css. This allows us to follow a good coding pattern to keep our concerns separated between layout semantics (html), logic (js), and presentation (css). We’re not going to modify the html of this page, instead we’ll just tweak the css to apply a bit of styling to our h1 tag to set the font to Comic Sans MS. Note, I don’t recommend making this particular change in your apps. This change is just for demonstration purposes! Open the DetailPage.css and add the following to it:

h1{
    font-family:'Comic Sans MS', cursive;
}

 

With that change, we now need to give the user the ability to navigate from the home page to our new page. In the home.html page, let’s add the highlighted line giving the user an anchor tag to click:

        <section aria-label="Main content" role="main">
            <p>Content goes here.</p>
            <a id="detailButton" href="#">View Detail</a>
        </section>

Finally, let’s add a click handler for the “button” in the home.js file:

  ready: function (element, options) {
      element.querySelector("#detailButton").addEventListener('click',
           function () { WinJS.Navigation.navigate('/pages/Detail/DetailPage.html') });
  }

Now that we're done, we can navigate to our page to view our handy work. Hit F5 to run the app to see your impressive L337 skillz.

image

Next, navigate to the detail screen by clicking your link.

image

Notice here, because we used the WinJS.Navigation.navigate method to move to this page rather than just setting the href on the anchor tag, we magically have the default back button to get back to the home page. Try clicking it now.

image

Compare the first screen shot with this one. Do you notice anything unusual? The page title is now the wrong font. If we look at the Solution Explorer while debugging, the situation starts to make sense. Notice here that the DetailPage.js is still loaded even though we have navigated back to the home page.

image

As I stated earlier, in WinJS applications, the js and css files are loaded when they are first used and retained in memory rather than being refetched for each page request as is done in web pages. Since the styles are applied in the order that they are fetched, the last version of the font that applied to the h1 is the one that came from DetailPage.css. We can’t just try to set the style explicitly again in the home.css, because it was already previously loaded, so it won’t be re-loaded again.

In this case, if we want to globally modify the style, we should make then change in the default.css located in the css folder of our project. If we want to modify the style only for the lifetime of our individual detail page, we need to preface the style with a page class that is specific to our page. Looking at our DetailPage.html, we can see that the page template wizard generated the necessary class for us already.

<body>
    <div class="DetailPage fragment">
        <header aria-label="Header content" role="banner">
            <button class="win-backbutton" aria-label="Back" disabled type="button"></button>
            <h1 class="titlearea win-type-ellipsis">
                <span class="pagetitle">Welcome to DetailPage</span>
            </h1>
        </header>
        <section aria-label="Main content" role="main">
            <p>Content goes here.</p>
        </section>
    </div>
</body>

Notice that the main div uses the “DetailPage fragment” class. With this we can preface the h1 style in the DetailPage.css file with the .DetailPage class selector to indicate that the style should only be applied to this page:

.DetailPage h1 {     font-family:'Comic Sans MS', cursive;
}

If we run the application again, we should see that when we navigate back to the home page, the font is (thankfully) no longer Comic Sans MS, but has reverted to the oh so much more wonderful Windows 8 default of Segoe UI. If you don’t’ believe me and want to try this out for yourself, feel free to type the code in above, or just download the project and try it yourself. I know, I could have told you about the download link in the beginning, but where’s the fun in that?

Have you run into this issue and found alternative solutions, I’d love to know what you thinq.

Posted on - Comment
Categories:
comments powered by Disqus