20 Protips For Writing Modern CSS

By Danny Markov

20-protips-for-writing-modern-css

In this post we want to share with you a collection of 20 useful conventions and best practices that are recommend by the CSS community. Some are tailored more towards beginners, and some are a bit advanced, but we hope everyone will find a cool trick they didn’t know about. Enjoy!


1. Beware of Margin Collapse

Unlike most other properties, vertical margins collapse when they meet. What this means is that when the bottom margin of one element touches the top margin of another, only the bigger of the two survives. Here is a simple example:

(Play with our code editor on Tutorialzine.com)

Instead of 70px between the red and blue square we have only 40px, the margin of the blue square isn’t taken into consideration at all. There are ways to battle this behavior, but it’s better to just work with it and use margins only going in one direction, preferably margin-bottom.


2. Use Flexbox For Layouts

The flexbox model exists for a reason. Floats and inline-blocks work, but they are all essentially tools for styling documents, not websites. Flexbox on the other hand is specifically designed to make it easy to create any layout exactly the way it was envisioned.

The set of properties that come with the flexbox model give developers lots of flexibility (no pun intended), and once you get used to them, doing any responsive layout is a piece of cake. Browser support nowadays is almost perfect, so there shouldn’t be anything stopping you from going full flexbox.

.container {
    display: flex;
    /* Don't forget to add prefixes for Safari */
    display: -webkit-flex;
}

We’ve featured a number of tips and trick with flexbox before on Tutorialzine. You can check them out here: 5 Flexbox Techniques You Need to Know About.


3. Do a CSS Reset

Although the situation has greatly improved over the years, there is still plenty of variation in the way different browsers behave. The best way to resolve this issue is to apply a CSS reset that sets universal default values for all elements, allowing you to start working on a clean style sheet that will yield the same result everywhere.

There are libraries like normalize.css, minireset, and ress that do this very well, correcting all imaginable browser inconsistencies. If you don’t want to use a library, you can do a very basic CSS reset yourself with these styles:

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

This may seem a bit harsh, but nullifying margins and paddings actually makes laying out elements much easier as there are no default spaces between them to take into account. The box-sizing: border-box; property is another good default, which we will talk about more in our next tip.


4. Border-box for All

Most beginners don’t know about the box-sizing property but it’s actually quite important. The best way to understand what it does is to look at it’s two possible values:

  • content-box (default) – When we set a width/hight to an element, that’s just the size for it’s content. All paddings and borders are on top of that. E.g. a
    has a width of 100 and padding of 10, our element will take up 120 pixels (100 + 2*10).
  • border-box – The padding and border are included in the width/height. A
    with width: 100px; and box-sizing: border-box; will be 100 pixels wide no matter what paddings or borders are added.

Setting border-box to all elements makes it so much easier to style everything, since you don’t have to do math all the time.


5. Images as Background

When adding images to your design, especially if it’s going to be responsive, use a

tag with the background CSS property instead of elements.

This may seem like more work for nothing, but it actually makes it much easier to style images properly, keeping their original size and aspect-ratio, thanks to backgorund-size, backgorund-position, and other properties.

(Play with our code editor on Tutorialzine.com)

A drawback of this technique is that the web accessibility of your page will take a slight hit, as images won’t be crawled properly by screen readers and search engines. This issue can be resolved by the awesome object-fit but it doesn’t have full browser support yet.


6. Better Table Borders

Tables in HTML are not fun. They are quirky, almost impossible to be made responsive, and overall difficult to style. For example, if you want to add simple borders to your table and its cells, you will most probably end up with this:

(Play with our code editor on Tutorialzine.com)

As you can see, there are quite a lot of repeating borders everywhere and it doesn’t look good. Here is a quick, hack-free way to remove all doubling borders: simply add border-collapse: collapse; to the table.

(Play with our code editor on Tutorialzine.com)

Much better!


7. Write Better Comments

CSS might not be a programming language but it’s code still needs to be documented. Some simple comments are all it takes to organize a style sheet and make it more accessible to your colleagues or your future self.

For larger sections of the CSS such as major components or media-queries, use a stylized comment and leave a couple of new lines after:

/*---------------
    #Header
---------------*/
header { }

header nav { }




/*---------------
    #Slideshow
---------------*/
.slideshow { }

Details in the design or less important components can be marked with a single-line comment.

/*   Footer Buttons   */
.footer button { }

.footer button:hover { }

Also, remember that CSS doesn’t have single line // comments, so when commenting something out you still need to use the /* */ syntax.

/*  Do  */
p {
    padding: 15px;
    /*border: 1px solid #222;*/
}

/*  Don't  */
p {
    padding: 15px;
    // border: 1px solid #222;  
}

8. Everyone Loves kebab-case

Class names and ids should be written with a hyphen (-) when they contain more then one word. CSS is case-insensitive so camelCase is not an option. A long time ago, underscores used to not be supported (they are now) which made dashes the default convention.

/*  Do     */
.footer-column-left { }

/*  Don't  */
.footerColumnLeft { }

.footer_column_left { }

When it comes to naming, you may also consider BEM, which follows a set of principles that add consistency and provide a component-based approach to development. You can read more about it in this excellent CSS-Tricks article.


9. Don’t Repeat Yourself

The values for most CSS properties are inherited from the element one level up in the DOM tree, hence the name Cascading Style Sheets. Let’s take the font property for example – it is almost always inherited from the parent, you don’t have to set it again separately for each and every element on the page.

Simply add the font styles that will be most prevalent in your design to the or element and let them trickle down. Here are some good defaults:

html {
    font: normal 16px/1.4 sans-serif;
}

Later on you can always change the styles for any given element. What we are saying is just to avoid repetition and use inheritance as much as possible.


10. CSS Animations with transform

Don’t animate elements by directly changing their width and height, or left/top/bottom/right. It’s preferred to use the transform() property as it provides smoother transitions and makes your intentions easier to understand when reading the code.

Here’s an example. We want to animate a ball and slide it out to the right. Instead of changing the value of left, it’s better to use translateX():

.ball {
    left: 50px;
    transition: 0.4s ease-out;
}

/* Not Cool*/
.ball.slide-out {
    left: 500px;
}

/* Cool*/
.ball.slide-out {
    transform: translateX(450px);
}

Transform, as well as all of its many functions (translate, rotate, scale, etc.) have almost universal browser compatibility and can be used freely.


11. Don’t DIY, Use A Library

The CSS community is enormous and there are constantly new libraries coming out. They serve all kinds of purposes, from tiny snippets to full-blown frameworks for building responsive apps. Most of them are open-source too.

Next time you are faced with a CSS problem, before you try to tackle it with all your might and hacks, check if there isn’t already a solution available on GitHub or CodePen.


12. Keep Selector Specificity Low

Not all CSS selectors are created equal. When novice developers write CSS they usually expect that selectors will always overwrite everything above them. However, this isn’t always the case, as we’ve illustrated in the following example:

(Play with our code editor on Tutorialzine.com)

We want to be able to add the .active class to any button and make it red. This won’t work here because our button has it’s background-color set with an ID selector, which has a higher selector specificity. The rule goes like this:

ID (#id) > Class (.class) > Type (e.g. header)

Specifity also stacks so a#button.active ranks higher than a#button. Using selectors with high specificity will cause you to constantly trump old selectors with even higher ones and eventually result in !important. This leads us into our next tip:


13. Don’t Use !important

Seriously, don’t. What is a quick fix now may end up causing lots of rewrites in the future. Instead, find why your CSS selector isn’t working and change it.

The only time when it’s acceptable to !important CSS rules is when you want to override inline styles from the HTML, which in itself is another bad practice to be avoided.


14. Caps Lock For Meaning, text-transform For Style

In the HTML, write upper case letters when you want to use them for their intended semantic meaning, like when you want to emphasize the importance of a word.

<h3>Employees MUST wear a helmet!</h3>

If you need to have some text in all caps for stylistic reasons, write the text normally in the HTML, and transform it to all-caps with CSS. It will look the same but your content will make more sense if taken out of context.

<div class="movie-poster">Star Wars: The Force Awakens</div>
.movie-poster {
    text-transform: uppercase;
}

The same goes for lowercasing and capitalizing strings – text-transform handles those just as well.


15. Em, Rem, and Pixel

There is a lot of debate whether people should use em, rem, or px values for setting the size of elements and text. Truth is, all three options are viable and have their pros and cons.

All developers and projects are different, so there can’t be any strict rules on when to use which. Here are, however, some tips and general good practices for each unit:

  • em – The value of 1 em is relative to the font-size of the direct parent. Often used in media-queries, em is great for responsiveness, but it can get really confusing tracing back the exchange rate of ems to pixels for each element (1.25em of 1.4em of 16px = ?).
  • rem – Relative to the font-size of the element, rem makes it really easy to scale all headings and paragraphs on the page. Leaving the with it’s default fontsize and setting everything else with rem is a great approach accessibility-wise.
  • px – Pixels give you the most precision but don’t offer any scaling when used in responsive designs. They are reliable, easy to understand, and present a good visual connection between value and actual result (15px is close, maybe just a pixel or two more).

Bottom line is, don’t be afraid to experiment, try them all and see what you like best. Sometimes em and rem can save you a lot of work, especially when building responsive pages.


16. Use a Preprocessor on Large Projects

You’ve heard about them – Sass, Less, PostCSS, Stylus. Preprocessors are the next step in the evolution of CSS. They provide features such as variables, CSS functions, selector nesting, and lots of other cool stuff, making CSS code easier to manage, especially in large projects.

For a quick example, here is a snippet of using CSS variables and functions directly in a style sheet with Sass:

$accent-color: #2196F3;

a {
    padding: 10px 15px;
    background-color: $accent-color;
}

a:hover {
    background-color: darken($accent-color,10%);
}

The only real drawback of preprocessors is that they need compiling to vanilla CSS, but if you are already using a build script in your project this shouldn’t be too much of a hassle.

To learn more about preprocessors, check out our tutorials on two of the most popular systems – Sass and Less.


17. Autoprefixers For Better Compatibility

Writing browser-specific prefixes is one of the most annoying things in CSS. They aren’t consistent, you never know exactly which ones you need, and if you do the actual process of placing them in your style sheet is a boring nightmare.

Thankfully, there are tools that automatically do that for you and will even let you decide which browsers you need supported:


18. Use Minified Code In Production

To improve the page load of your websites and apps you should always use minified resources. The minified version of your code will have all whitespace and repetitions removed, reducing the total file size. Of course, this process also makes style sheets completely unreadable so always keep a .min version for production and a regular version for development.

There are many different ways to minify CSS code:

Depending on your workflow, any of the above options can be used, but it’s recommended to automate the process in one way or another.


19. Caniuse Is Your Friend

The different web browsers still have lots of compatibility inconsistencies. Use canisue or a similar service to check if what you are using is widely supported, if it needs prefixes, or if it causes any bugs in a certain platform.

Just checking caniuse isn’t enough though. You also need to do tests (either manually or through a service) as sometimes layouts break for no obvious reasons. Knowing the preferred browsers of your userbase also helps a lot, since you can see where good support is most crucial.


20. Validate

Validating CSS might not be as important as validating HTML or JavaScript code, but running your code through a CSS Linter can still be very helpful. It will tell you if you’ve made any mistakes, warn you about bad practices, and give you general tips for improving the code.

Just like minfiers and autoprefixers, there are plenty of free validators available:

Source:: Tutorialzine.com

Quick Tip: Working with the JavaScript Battery API

By Danny Markov

working-with-js-battery-api

In this tutorial we’re going to show you how to use the JavaScript Battery API to improve the user experience for people in desperate need of a charger. We’ll look at the Battery API itself, as well as some techniques for getting the most out of every drop of the most precious of resources!

Monitoring Battery Life

The JavaScript Battery Status API talks to the device’s hardware and gives us accurate data about the system’s charging state. It can be accessed via the promise based navigator.getBattery() interface, or directly via the navigtator.battery object, although the second option is now deprecated and overall not recommended.

Some browsers lack support for the Battery API (you guessed it, they are Safari and IE), so a quick support check can go a long way in terms of debugging:

if(navigator.getBattery){
    // Battery API available.
    // Rest of code goes here.
}
else{
    // No battery API support.
    // Handle error accordingly.
}

Once we are sure that your user can access the API, grabbing the needed information is really easy:

navigator.getBattery()
    .then(function(batteryManager) {
        
        // Get current charge in percentages.
        var level = batteryManager.level * 100;

    })
    .catch(function(e) {
        console.error(e);
    });

The getBattery() method returns a promise and resolves with a BatteryManager object containing various information about the current status of the hardware:

  • batteryManager.level – The current charge, returns a float between 0 and 1.
  • batteryManager.charging – Is the device on power supply or not, returns true/false.
  • batteryManager.chargingTime – Remaining time in seconds till completely charged.
  • batteryManager.dischargingTime – Remaining time until battery is dead.

It also provides events that can be used to monitor changes in any of the above properties.

  • BatteryManager.onlevelchange
  • BatteryManager.onchargingchange
  • BatteryManager.onchargingtimechange
  • BatteryManager.ondischargingtimechange

Combining the raw data with the event listeners, we can easily set up a watcher for low battery levels:

navigator.getBattery()
    .then(function(battery) {    
        battery.onlevelchange = function() {

            if(battery.level<30 && !battery.charging) {
                powerSavingMode = true;
            }

        }
    });

Once we know how much juice is left in the device we can adapt the app and turn on a power saving mode if its needed.

Preserving energy

The biggest battery drainer of all components is the screen. This is especially true on smartphones and tablets where often CPUs are energy preserving, while the screens have super-ultra-full-QHD resolution with the brightness of two suns.

The first and foremost thing we can do to address this issue is limit the amount of light the screen is emitting. JavaScript doesn’t have the authority to control the brightness directly, but we can do so by changing the color pallet to a darker theme.

Dark colors need less energy to be displayed, with more than 50% reduction on AMOLED screens.

The next thing we can do is limit the amount and size of requests to external resources. The biggest drainers here are high-res images, advertisements, and large JavaScript libraries, as they need a lot of bandwidth to download.

Here we have two options – load an alternative, more optimized resource with a smaller footprint, or, fully remove the image/advert if it doesn’t portray any essential information. Any background images, videos or animations should be removed.

removed-ads

Removing non-essential elements from the page makes the vital content easier to reach when in a hurry.

The last battery-drainer we will talk about is JavaScript. We already mentioned that download large libraries and frameworks is bad enough, but the actual parsing and execution of JS block can also lead to unnecessary spending.

JavaScript animations that cause constant redrawing of elements on the screen, listening for notifications form the server, and multiple AJAX requests can all drain the battery just a tiny bit, but it quickly adds up. According to this study, the JavaScript code consumes ~7% of Yahoo’s total rendering energy, ~17% on Amazon, and more than 20% on YouTube.

App With Powersaving Mode

We have showcased some of the above concepts in a simple demo app. It consists of a static website which reacts to the amount of battery left. When it gets below 30% the app goes into PowerSaving and turns darker, stops all animations, and removes all ads.

For demonstration purposes our app works with a virtual battery to enable quick toggling between fully charged and almost dead. It does not contain much code for working with the Battery API itself.

Our Demo App

Our Demo App

You can get the full code for the demo from the Download button near the top of the article. It’s written in Vue.js for easier data monitoring and has lots of comments to guide you through all that is happening.

Further Reading

If you want to find out more about the Battery Status API or about ways your precious battery is running down the drain, check out these excellent resources:

Battery Status API on MDN – here
The BatteryManager interface on MDN – here
5 Ways to Improve Battery Life in Your App – here
Who Killed My Battery: Analyzing Mobile Browser Energy Consumption – here

Source:: Tutorialzine.com

15 Interesting JavaScript and CSS Libraries for August 2016

By Danny Markov

interesting-libraries-august-2016

Our mission at Tutorialzine is to keep you up to date with the latest and coolest trends in web development. That’s why every month we release a handpicked collection of some of the best resources that we’ve stumbled upon and deemed worthy of your attention.

Our libraries for August 2016 follow modern conventions and have as little dependencies as possible, modular architectures, and simple APIs to ease the headaches caused by JavaScript fatigue.


Aquarelle

Library for creating magnificent watercolor effects. You can use Aqaurelle to add a fade-in animation to images and make them look as they are being painted on by smudged drops of paint. Built on top of the 3D canvas library Three.js.


SuperEmbed.js

SuperEmbed is a no-dependencies library that detects embeded videos on the page and makes them responsive without messing up their original aspect ratio. It works with many popular media sources including YouTube, Vimeo, Twitch, Vine, and many others.


Vuikit

A Vue.js implementation of the popular UIkit front-end framework. The developers behind Vuikit have recreated most of UIkit’s components and made them work naturally with Vue and it’s data driven logic so that you can now build responsive Vue.js apps with little to no effort.


Staticman

With Staticman you can add dynamic content to your static Jekyll websites. If your site is hosted on GibHub pages you can implement a comment section or any other user content form, which when submitted will push the data from the form as a file to your repository. Staticman also gives the option to push new content to a separate branch, so that it won’t show up on the website until the pull request is approved.


Choices.js

Library for creating better form fields. It offers many improvements over the default input elements like multiple entries per field, prettier select boxes, and linked form fields. Choices is written in vanilla JavaScript in it’s entirety so it’s very lightweight.


Flatpickr

You may have heard of Flatpickr as it is one of the most widely used date and time pickers available. We are including it in our list because it’s authors have recently announced version 2.0, introducing lots of new features like jQuery compatibility, improved performance, SVG icons, and more.


Uppy

JavaScript file uploader that can fetch files from services such as Dropbox and Instagram, as well as from a local hard drive. It has support for resumable uploads and is separated into opt-in modules to keep it lightweight. Uppy is still in the early stages of development but you can already tell it’s a very promising project.


Skippr

Skippr is a jQuery slideshow plugin, and from all the jQuery slideshow plugins that we’ve seen, this one is probably the easiest one to use. Installation is simple, the requried HTML markup is clean, and the jQuery method takes a straightforward options object.


Howler.js

Modern library for working with audio in the web. Howler is modular, dependency-free, and fully supported in all mainstream browsers. It provides developers with the entire set of tools and controls needed for implementing sound into a website or app.


Overhang.js

Overhang.js adds stylish and well-animated pop-up notifications on top of any DOM element of your choice. This tiny jQuery plugin offers a number of modal types that can be easily implemented as a replacement for the default alert, prompt and confirm dialogs.


Baffle.js

Baffle is a tiny JavaScript library for concealing text from the screen. The information you want to hide can be camouflaged with rectangular blocks, random symbols, or any other strings. The library provides all the methods you may ever need as well as some animation options.


Jets

Jets is a clever library that utilizes CSS selectors to do blazing fast searches. Instead of hiding non-matching search results one-by-one with individual attributes, Jets creates a single tag on the parent container with a dynamic CSS selector that filters out elements based on their content.


Intercooler.js

Intercooler.js allows developers to quickly implement AJAX directly in the HTML. By adding a specific HTML attribute to your links and buttons you can enable them to send GET, POST, or other requests to a URL. The data returned from the server can also be accessed through HTML attributes.


SecLists

A gigantic collection of sample data for security assessments. The data comes in lists calssified in various types (usernames, passwords, URLs, etc.), with each type containing dozens of lists full of dummy entries or actual common passwords and usernames that people use (e.g. 500-worst-passwords.txt or top_1000_usa_malenames_english.txt).


Jumpsuit

Efficient React/Redux framework that brings together the best standards in JavaScript development and allows you to get a head start on your apps. Jumpsuit gives you a helpful CLI that simplifies setting up all the libraries and tasks needed for working with React.

Source:: Tutorialzine.com

Building Your First App With Vue.js

By Danny Markov

building-your-first-app-with-vuejs

Today we’re going to exercise our Vue.js skills by building a simple app for browsing reddit posts. We’re going to construct the whole thing from scratch to demonstrate just how easy it is to create user interfaces with a framework like Vue.

This tutorial requires you to have at least some basic knowledge of JavaScript and Vue.js. If you aren’t familiar with Vue.js at all, we advise you to go and check out our article 5 Practical Examples For Learning Vue.js, where we show many of the core concepts with practical code snippets.

The App

What we want from our application is simply to fetch the feed from a number of subbreddits and display them. Here is what the end result will look like:

Our Vue.js App

We will have six separate subreddit feeds showing five posts each. The posts have links to the content and discussion on reddit, as well as some other details. For the sake of simplicity we have omitted features such as adding/removing subreddits and doing searches, but they can be easily added on top of the existing app.

Setting Up The Workspace

You can download the full source code for the reddit browser app from the Download button near the top of the article. Before we actually look at the code, let’s make sure that everything is setup properly. Here is an overview of the file structure:

Our project's folder

Our project’s folder

As you can see it’s quite basic: we just have one HTML file, one CSS file, a script.js containing our JavaScript code. We’ve also added local copies of the Vue.js and Vue-resource libraries, but you can use a CDN if you prefer.

Thankfully, Vue.js doesn’t require any special configuration, so it should work straight out of the box. To start the app we just have to create a global Vue instance:

new Vue({
    el: 'body'
});

The only thing left to do now is start a local web server to enable cross-origin AJAX requests to the reddit API. The easiest way to do this on OS X/Ubuntu is by running the following command from the project’s directory:

python -m SimpleHTTPServer 8080

If everything is done properly our project should be available at localhost:8080.

Creating Custom Components

Our app is going to need two reusable components – one for the Posts, and another for Subreddits. The two components will be in a Child-Parent relationship, meaning that the Subreddit component will have multiple Posts nested in it.

Components Structure

Components Hierarchy

Let’s start with the Subreddit component, and more specifically it’s JavaScript:

// Parent | Subreddit component containing a list of 'post' components. 
var subreddit = Vue.component('subreddit',{
    template: '#subreddit',
    props: ['name'],

    data: function () {
        return { posts: [] }
    },

    created: function(){
        this.$http.get("https://www.reddit.com/r/"+ this.name +"/top.json?limit=5")
        .then(function(resp){
            this.posts=resp.data.data.children;
        });
    }
});

Here we define the new component under the name subreddit. In props we provide an array with all the parameters our component can receive – in this case it is just the name of the subbreddit we want to browse. Now if we want to add a subreddit block to the HTML we will use this markup:

<subreddit name="food"></subreddit>

The data property defines what variables are needed for each instance of the component and their default values. We will start with an empty posts array, and populate it in the created method. When a tag is created, Vue will take its name property, make a call to the reddit API to fetch the top 5 posts from the subreddit with that name, and save them in this.posts. For the HTTP requests we’ve used the vue-resource library instead of jQuery, since it is way tinier and automatically binds the correct context for this.

After we’ve acquired everything we need in the model, Vue.js will automatically render our Subreddit components. The actual view that the user sees is defined in a template in index.html:

<template id="subreddit">

    <div class="subreddit">
        <h2>{{ name | uppercase }}</h2>

        <ul class="item-list">
            <li v-for="obj in posts">
                <post :item="obj"></post>
            </li>
        </ul>
    </div>

</template>

Personally, I like to wrap all the elements of a component in a div container. This makes them easier to style and also seems more semantic (to me at least). Inside that container we have a title (the uppercase filter comes built-in with Vue) and an unordered list iterating over the elements returned from the reddit API call.

If you look closely at the HTML, you’ll also notice we are using a tag. This isn’t some new fancy HTML element – it’s our child component!

// Child | Componenet represiting a single post.
var post = Vue.component('post', {
    template: "#post",
    props: ['item']
});

Post components will expect a object called item containing all of the information about a single post on reddit – things like title, URLs, number of comments, etc. As we saw earlier, this is done in a v-for loop inside the Subreddit (parent) component:

<li v-for="obj in posts">
    <post :item="obj"></post>
</li>

The colon prefixing :item="obj" is very important. It tells Vue that we are proving a JavaScript object called obj (as opposed to the string "obj"), allowing us to pass the data from the v-for.

Now that we have all the needed properties for a post, we can display them. The template looks scary at first, but really isn’t:

<template id="post">

    <div class="post">
        <a   :href="item.data.url" :style="item.data.thumbnail | setAsBackground" 
             target="_blank" class="thumbnail"></a>

        <div class="details">
            <a :href="item.data.url" :title="item.data.title" target="_blank" class="title">
                {{ item.data.title | truncate}}
            </a>          
            
            <div class="action-buttons">
                <a href="http://reddit.com{{ item.data.permalink }}" title="Vote">
                    <i class="material-icons">thumbs_up_down</i>
                    {{item.data.score}}
                </a>

                <a href="http://reddit.com{{ item.data.permalink }}" title="Go to discussion">
                    <i class="material-icons">forum</i>
                    {{item.data.num_comments}}
                </a>
            </div>
        </div>
    </div>
    
</template>

The only thing worth mentioning here is the use of the setAsBackground and truncate filters. In contrast to the uppercase filter we used earlier, they don’t come bundled with Vue and we had to make them ourselves.

Creating Custom Filters

Defining filters is quite easy. The Vue.filter() method provides us with the incoming string data, which we can transform whatever way we want and then simply return.

The first filter we’ll need takes the preview image for a post and creates a CSS rule setting it as background. We use this to set the inline styles with less effort.

It takes one parameter: the URL for the image. If that’s not available a placeholder image is shown instead.

// Filter that takes an image url and creates a CSS style.
Vue.filter('setAsBackground', function(value) {
    if(value && value!='self' && value!='nsfw') {
        return 'background-image: url(' + value + ')';  
    }
    else {
        return 'background-image: url(assets/img/placeholder.png)';   
    }
});

Our other filter takes strings and truncates them if they are too long. This is applied to the post titles, which often are way too lengthy for the design we had in mind.

// Filter for cutting off strings that are too long.
Vue.filter('truncate', function(value) {
    var length = 60;

    if(value.length <= length) {
        return value;
    }
    else {
        return value.substring(0, length) + '...';            
    }
});

The Full Code

Below we’ve listed all of the files for the app, so that you can look through the full code and get a better idea how the whole thing works.

/*-----------------
    Components 
-----------------*/

// Parent | Subreddit component containing a list of 'post' components. 
var subreddit = Vue.component('subreddit',{
    template: '#subreddit',
    props: ['name'],

    data: function () {
        return { posts: [] }
    },

    created: function(){
        this.$http.get("https://www.reddit.com/r/"+ this.name +"/top.json?limit=3")
        .then(function(resp){
            this.posts=resp.data.data.children;
        });
    }
});


// Child | Componenet represiting a single post.
var post = Vue.component('post', {
    template: "#post",
    props: ['item']
});


/*-----------------
   Custom filters 
-----------------*/

// Filter for cutting off strings that are too long.
Vue.filter('truncate', function(value) {
    var length = 60;

    if(value.length <= length) {
        return value;
    }
    else {
        return value.substring(0, length) + '...';            
    }
});


// Filter that takes an image url and creates a CSS style.
Vue.filter('setAsBackground', function(value) {
    if(value && value!='self' && value!='nsfw') {
        return 'background-image: url(' + value + ')';  
    }
    else {
        return 'background-image: url(assets/img/placeholder.png)';   
    }
});


/*-----------------
   Initialize app 
-----------------*/

new Vue({
    el: 'body'
});
<!DOCTYPE html>
<html>
<head>
    <title>Your First App With Vue.js</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="assets/css/styles.css">
</head>
<body>
    <div class="container">
        <subreddit name="aww"></subreddit>
        <subreddit name="space"></subreddit>
        <subreddit name="gifs"></subreddit>
        <subreddit name="food"></subreddit>
        <subreddit name="comics"></subreddit>
        <subreddit name="sports"></subreddit>
    </div>


    <template id="subreddit">
        <div class="subreddit">
            <h2>{{ name | uppercase }}</h2>
            <ul class="item-list">
                <li v-for="obj in posts">
                    <post :item="obj"></post>
                </li>
            </ul>
        </div>
    </template>

    <template id="post">
        <div class="post">
            <a   :href="item.data.url" :style="item.data.thumbnail | setAsBackground" 
                 target="_blank" class="thumbnail"></a>
            <div class="details">
                <a :href="item.data.url" :title="item.data.title" target="_blank" class="title">
                    {{ item.data.title | truncate}}
                </a>          
                
                <div class="action-buttons">
                    <a href="http://reddit.com{{ item.data.permalink }}" title="Vote">
                        <i class="material-icons">thumbs_up_down</i>
                        {{item.data.score}}
                    </a>

                    <a href="http://reddit.com{{ item.data.permalink }}" title="Go to discussion">
                        <i class="material-icons">forum</i>
                        {{item.data.num_comments}}
                    </a>
                </div>
            </div>
        </div>       
    </template>

    <script src="assets/js/vue.js"></script>
    <script src="assets/js/vue-resource.min.js"></script>
    <script src="assets/js/script.js"></script>
</body>
</html>
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

a{
    text-decoration: none;
}

a:hover{
    text-decoration: underline;
}

html{
    font: normal 16px sans-serif;
    color: #333;
    background-color: #f9f9f9;
}

.container{
    padding: 27px 20px;
    margin: 30px auto 50px;
    max-width: 1250px;
    display: flex;
    flex-wrap: wrap;
    flex-direction: row;
    background-color: #fff;
    box-shadow: 0 0 1px #ccc;
}

/* Subreddit component */

.subreddit{
    flex: 0 0 33%;
    min-width: 400px;
    padding: 20px 42px;
}

.subreddit h2{
    font-size: 18px;
    margin-bottom: 10px;
}

.subreddit .item-list{
    border-top: 1px solid #bec9d0;
    padding-top: 20px;
    list-style: none;
}

.subreddit .item-list li{
    margin-bottom: 17px;
}

/* Post component */

.post{
    display: flex;
}

.post .thumbnail{
    display: block;
    flex: 0 0 60px;
    height: 60px;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
    margin-right: 10px;
    border-radius: 4px;
    margin-right: 12px;
}

.post .details{
    display: flex;
    flex-direction: column;
}

.post .details .title{
    font-size: 15px;
    margin-bottom: 3px;
    color: #04477b;
}

.post .details .title:visited{
    color: purple;
}

.post .details .action-buttons a{
    font-size: 11px;
    margin-right: 4px;
    display: inline-block;
    color: #666;
}

.post .details .action-buttons i{
    font-size: 10px;
    margin-right: 1px;
}

@media(max-width: 1250px){

    .container{
        justify-content: center;
        margin: 30px 30px 50px 30px;
    }
}

@media(max-width: 500px){

    .subreddit{
        min-width: 300px;
        padding: 20px 15px;
    }
}

Note that after creating our two components, the entire app interface comes down to:

<div class="container">
    <subreddit name="aww"></subreddit>
    <subreddit name="space"></subreddit>
    <subreddit name="gifs"></subreddit>
    <subreddit name="food"></subreddit>
    <subreddit name="comics"></subreddit>
    <subreddit name="sports"></subreddit>
</div>

The JavaScript file isn’t too large either and this is one of my favorite things about Vue. It does so much of the work for us that in the end we are left with a very clean and comprehensive piece of code.

Further Reading

The main focus of this tutorial was to show the process of building a simple Vue.js app. To keep it short we haven’t stopped to explain every tiny syntax peculiarity, but worry not! There are many awesome resources where you can learn the basics:

  • The official Vue.js starting guide and docs – here.
  • Excellent video series from Laracasts – here.
  • Our very own article: 5 Practical Examples For Learning Vue.js – here.

This concludes our Vue.js tutorial! We hope that you’ve had lots of fun with it and that you’ve learned a thing or two. If you have any suggestions or questions, feel free to leave a message in the comment section below :)

Source:: Tutorialzine.com