According to some historical records, some people out there have boundless energy, loads of free time, and ambition enough to make a dictator blush. These people are called “not parents”, “morning people”, and “annoying”. Some say these people invented the Side Hustle().
Those historical records are wrong. The Side Hustle was invented long ago by people who just needed more money. Could have been Eve for all we know. Now we live in a gig economy, for better and worse, and everyone has a side hustle of some kind. That includes us web designers.
We get into them to make some extra cash, to add to our portfolios, to build name recognition, to build a network, as a creative outlet, or all of the above. As we get into 2019, we thought it’d be fun to go over some of the more common side hustles for web designers, and examine which might be the best to get into this year:
1. The Self-Hosted Blog
Ah the self-hosted blog, where you’re in full control of the branding, all the content, and you have to do everything by yourself. Why would you blog on your own site when Medium exists, and does half your marketing for you? Because the uhh… the slight community issues with Tumblr last year clearly demonstrate how quickly creators can get screwed by policy changes when they’re on a platform they don’t own. Ask any Youtuber, too. They’ll tell you.
Effort: A minimum 10-20 minutes of work. Can be expanded upon as much as you want.
Financial prospects: Depends entirely upon the following you build. Financial returns may be seen in increased clients, rather than directly receiving revenue from the blog.
Should you? Medium proves the demand for blogs has not died, and likely never will. Just about every creative should probably have one.
Free idea for devs out there: build a self-hosted blogging platform with social features that allow you to connect to other blogs. Like a self-hosted Tumblr, with a feed and everything. Well, maybe connecting to other blogs should be optional. Look at Mastodon for a general model of the idea.
2. Authority Site
An authority site is like a blog with no dates and you don’t have to update nearly as often, as they generally feature perennially useful information. They typically run ads for revenue, and the really good ones can generate reasonable passive income. It can be about one of your non-web design interests, or some bit of our own industry that may not be completely understood yet, e.g. Grid by Example.
Effort: More initial effort than blog, but less in the long term. It’s kind of like writing a mini-wiki.
Financial prospects: Again, varies greatly depending on traffic, and your monetization strategy. Sometimes these are best used as portfolio pieces.
Should you? There’s no real reason why not. Good information is search-friendly information, and launching a few of these could help you build up a reputation, if nothing else.
3. Themes, Plugins, and Other Resources
What the title says. You can always make stuff for your fellow designers and front-end developers to use in their own sites. Everyone loves stuff that makes their own lives a bit easier, and gets their own work done faster.
Effort: Depends on what you make. A single icon could be the work of a day. An icon set is another matter. Anything with code gets real interesting, because code generally requires maintenance.
Financial prospects: Making things for free earns you goodwill. Selling them makes money, but you’ll hardly be the only stall in the marketplace.
Should you? The market is saturated right now. Unless what you’re creating fills a specific and under-served niche, you’re going to face very stiff competition. You’d better know, for a fact, that you’re going to stand out.
4. Contribute to an Existing OSS Project
Ah, the beauty of open source software: anyone can make it. Okay, if you’re primarily a graphics guy, you may stick to creating assets for the project of your choice, but that is something that is still good and necessary.
Effort: Depends on what you contribute. Expect to spend some time figuring that out with other people, and factor in time for that communication.
Financial prospects: Prospects for immediate financial gain are poor to nonexistent.
Should you? If you don’t need extra money any time soon, but do need contacts, yeah. Go for it. Having your name on some OSS projects can be a big resume booster, and you’re giving back to the community in a big way.
5. Start a YouTube Channel or Twitch Stream
Video… it’s like podcasting, but with more work. Interestingly enough—and considering that web design is a very visual discipline—there seems to be a lot more podcasts and blogs of note in the web design space than there is video content, even as other industries trend toward video. Mostly I’ve seen app tutorials, some videos about the very basics, with a few vlog-style shows thrown in. These are all good things, but there’s room for growth. Heck, a lot of the content I’ve seen was made by marketers.
Effort: Loads of effort.
Financial prospects: Ad revenue on YouTube is a notoriously finicky thing, and building an audience takes time. Between patron, sponsors, and ads, Youtube videos and/or streaming can be turned into a full-time career, but that’s a long-term thing.
Should you? If you have the time (you do need a fair bit of it), and can eventually put a budget together for some entry-level hardware, it may be worth getting into the video space, ‘cause I don’t think it’s quite saturated.
6. Public Speaking
Stand up in front of people, sweat profusely, and stammer through a presentation. Then do it again and again until you’re good, and can effectively convey your knowledge to others.
Effort: There’s writing, nerves, and sometimes a bit of travel. It’s not the hardest thing you can do, but neither is it for the faint of heart.
Financial prospects: Local events are good for networking, but you may have to speak for free, or even pay to speak, depending on the event. Get real good, and conference organizers might pay you to come speak. Don’t expect to make a living, but it’s not bad for a side hustle.
Should you? If you’re comfortable with public speaking, go for it. Check out local events, and go to one or two of them. Get a feel for the audience, and then decide if you have something to share that they might need.
7. Start Your Own Events
Hosting events means networking opportunities, having fun, and making a decent bit of cash once the events start to grow. It’s a great way to bring the local design community together and learn. Of course, you need to make sure there aren’t maybe too many events like your in your area, maybe try to pick a unique theme, but it may be worth it.
Effort: HAHAHAHAHAHAHAH YES LOTS OF EFFORT. Obviously, if you keep the events small, it’s not too big a deal. It’s like a second business. But if it really starts to grow, running events could quickly take up a lot of room in your life.
Financial prospects: Decent, if you get people showing up.
Should you? Only if you really, really like talking to people, managing people, dealing with people’s complaints, scheduling for other people, chasing other people, and basically doing a whole lot of undesignery stuff.
And whatever you do, remember to have fun with it. No point in a side hustle that isn’t fun.
W3C’s CSS Working Group often gives us brilliant CSS features to experiment with. Sometimes we come across something so cool that sticks a grin on our face, but it vanishes right away because we think, “that’s great, but what do I do with it?” The element() function was like that for me. It’s a CSS function that takes an element on the page and presents it as an image to be displayed on screen. Impressive, but quixotic.
Below is a simple example of how it works. It’s currently only supported in Firefox, which I know is a bummer. But stick with me and see how useful it can be.
<div id="ele">
<p>Hello World! how're you?<br>I'm not doing that<br>great. Got a cold 😷</p>
</div>
<div id="eleImg"></div>
The element() function (with browser prefix) takes the id value of the element it’ll translate into an image. The output looks identical to the appearance of the given element on screen.
When I think of element()‘s output, I think of the word preview. I think that’s the type of use case that gets the most out of it: where we can preview an element before it’s shown on the page. For example, the next slide in a slideshow, the hidden tab, or the next photo in a gallery. Or… a minimap!
A minimap is a mini-sized preview of a long document or page, usually shown at on one side of the screen or another and used to navigate to a corresponding point on that document.
You might have seen it in code editors like Sublime Text.
CSS element() is useful in making the “preview” part of the minimap.
Down below is the demo for the minimap, and we will walk through its code after that. However, I recommend you see the full-page demo because minimaps are really useful for long documents on large screens.
If you’re using a smartphone, remember that, according to the theory of relativity, minimaps will get super mini in mini screens; and no, that’s not really what the theory of relativity actually says, but you get my point.
If you’re designing the minimap for the whole page, like for a single page website, you can use the document body element for the image. Otherwise, targeting the main content element, like the article in my demo, also works.
#minimap {
background: rgba(254,213,70,.1) -moz-element(#article) no-repeat center / contain;
position: fixed; right: 10px; top: 10px; /* more style */
}
For the minimap’s background image, we feed the id of the article as the parameter of element() and, like with most background images, it’s styled to not repeat (no-repeat) and fit inside (contain) and at center of the box (center) where it’s displayed.
The minimap is also fixed to the screen at top right of the viewport.
Once the background is ready, we can add a slider on top of it and it will serve to operate the minimap scrolling. For the slider, I went with input: range, the original, uncomplicated, and plain HTML slider.
#minimap-range {
/* Rotating the default horizontal slider to vertical */
transform: translateY(-100%) rotate(90deg);
transform-origin: bottom left;
background-color: transparent; /* more style */
}
#minimap-range::-moz-range-thumb {
background-color: dodgerblue;
cursor: pointer; /* more style */
}
#minimap-range::-moz-range-track{
background-color: transparent;
}
Not entirely uncomplicated because it did need some tweaking. I turned the slider upright, to match the minimap, and applied some style to its pseudo elements (specifically, the thumb and track) to replace their default styles. Again, we’re only concerned about Firefox at the moment since we’re dealing with limited support.
All that’s left is to couple the slider’s value to a corresponding scroll point on the page when the value is changed by the user. That takes a sprinkle of JavaScript, which looks like this:
onload = () => {
const minimapRange = document.querySelector("#minimap-range");
const minimap = document.querySelector("#minimap");
const article = document.querySelector("#article");
const $ = getComputedStyle.bind();
// Get the minimap range width multiplied by the article height, then divide by the article width, all in pixels.
minimapRange.style.width = minimap.style.height =
parseInt($(minimapRange).width) * parseInt($(article).height) / parseInt($(article).width) + "px";
// When the range changes, scroll to the relative percentage of the article height
minimapRange.onchange = evt =>
scrollTo(0, parseInt($(article).height) * (evt.target.value / 100));
};
The dollar sign ($) is merely an alias for getComputedStyle(), which is the method to get the CSS values of an element.
It’s worth noting that the width of the minimap is already set in the CSS, so we really only need to calculate its height. So, we‘re dealing with the height of the minimap and the width of the slider because, remember, the slider is actually rotated up.
Here’s how the equation in the script was determined, starting with the variables:
x1 = height of minimap (as well as the width of the slider inside it)
y1 = width of minimap
x2 = height of article
y2 = width of article
x1/y1 = x2/y2
x1 = y1 * x2/y2
height of minimap = width of minimap * height of article / width of article
And, when the value of the slider changes (minimapRange.onchange), that’s when the ScrollTo() method is called to scroll the page to its corresponding value on the article. ?
Fallbacks! We need fallbacks!
Obviously, there are going to be plenty of times when element() is not supported if we were to use this at the moment, so we might want to hide the minimap in those cases.
A good rule of thumb to remember is that, for regular web browsing, improvements in latency would be more beneficial than improvements in bandwidth, and that improvements in bandwidth are noticed more when dealing with larger files.
What makes a good website? Depending on what industry you’re in, or your preferences, that answer may be a little different from person to person. There are a few key factors that make up a good website, but depending on the experience the owner is trying to give the audience, it’s never quite the same. With that said, today we’re going to focus on some of the elements that go into a good real estate website design.
As you might expect, a real estate website is a very specific niche. Yes, there are lots of different houses displaying different styles, but the goal of the website is very specific: sell houses. So what exactly goes into real estate website design? Let’s dive a little deeper:
Beautiful images
It is incredibly hard to sell a product online with terrible pictures. If the customer can’t get a good sense of what the house looks like from a computer screen, they may get the wrong impression, and lookover a house completely. High-quality, detailed images are absolutely vital to the overall design of the website.
You should try to provide the best images possible for the listings, yes, but that theme should carry throughout the entire website. Don’t cut any corners.
Let your images do the talking
You know that phrase, “A picture is worth a thousand words”? That phrase rings incredibly true in the real estate business. Working off of our last point, if you have high-quality images of beautiful homes, you can easily implement them into the main theme of the overall sight.
Remember, people are visiting these websites for one thing and one thing only: to look at beautiful houses. What better way to please them than to give them what they want, front and center?
Take a look at Piercommercial.com, for example. It’s a simple, clean design that isn’t overwhelmed by tabs and sidebars. They’ve provided all the necessary information you need as a potential buyer, and topped it off with a nice image.
Include client testimonials
Granted, this is a great idea for any website selling a product or service, but you can understand why. Testimonials are a great way to include custom content that no other website can obtain. Each customer served or home sold produces a unique, one-of-a-kind experience that just simply can’t be duplicated naturally.
Besides that, a real estate website is all about pulling in traffic, and converting them to customers. The absolute best way to do that is to include past experiences that resulted in a happy customer. You can huff and puff all day long about how awesome you are at selling houses, but the average customer will believe another satisfied customer over you 9 times out of 10.
All of that being said, you’ll want to include images that represent the market you’re in. It doesn’t make much sense for a commercial real estate agent to use images of a country cottage. Perhaps the best practice would be to use images of homes or buildings that you’ve sold in the past.
Make it mobile friendly
It kind of goes without saying at this point that any website design should be created with mobile users in mind. In this case, we’re talking about real estate website design, which means that you’ll have clients out and about, going house to house as they find them.They’ll need a quick way to look up some information about the house that they very well could be standing right in front of.
As time goes on, the need for more mobile friendly websites will increase to a point where it will pretty much be unavoidable. So, if your website isn’t already created with mobile users in mind, you have homework to do.
Keep the navigation simple
There’s no need to get fancy with the navigation in your real estate website design. The best practice in this case would be to be straightforward. Again, this is something that a lot of websites struggle with. While it is appropriate to be a little silly or playful on some websites, a real estate page should be simple and professional.
I know, I know, professional can be boring, but it will help you in the end. You have to remember what kind of an audience you’re reeling in. most of the time, you’ll have people that want to get in, find what they’re looking for, and get out. Make it simple and straightforward, and it’ll avoid any potential confusion.
Focus on speed
Real estate websites contain a lot of information. This, of course, can result in very slow loading times, which isn’t a good thing. In fact, if your website loads slowly, not only will potential, high-paying clients leave, Google will, too. With that said, you should take every chance you get to improve loading speeds.
There are a few ways to help your site load faster, but perhaps the best and most widely used method is condensing image files. For a website with loads of images, it’s pretty important that all of their file sizes are as small as they can be without compromising the quality of the image itself. There are lots of free softwares that will help you do this online.
Create area profiles
Most people, when searching for their new home, know exactly the area they want to live in. if you create an area profile, it will help you in two ways:
First, it will really speed up the search process that everyone goes through when looking for a home. They don’t want to look at every house available in the state, or even city. They want to look neighborhood by neighborhood.
Second, it really helps with SEO search results. When someone is looking for a house in a specific neighborhood, they type ,”Homes for sale” and then the name of the neighborhood. If you’ve created a profile dedicated to such neighborhood, you’ll rank for it. It’s a win-win.
The conclusion
Real estate website design isn’t any sort of new industry or practice. It’s been around for quite a while, actually, but it does change. Although there are plenty of experimental methods out there (as there are for just about everything), there are methods that remain true to success. If you’re struggling with your real estate website design, or maybe just looking for ways to improve on it, give these tips a shot.
Over the years, WordPress has integrated Virtual Reality(VR) through 360 panoramic images and its no question that VR and AR (Augmented Reality) are the next best innovations to embrace.
People have always been interested in Virtual Tours where they can navigate and move about freely. And in the past few years, the WordPress community attempted to contribute by creating plugins to set up virtual tours using 360 panoramic images.
The idea is, rather than scrolling across a flat image left or right, how about you can move about in a 3D space and look around a house or any particular location as if you are actually taking a tour.
How Virtual Tour Creators Came About In WordPress
A few years back, people resorted to virtual video tours which cost tons of money in hiring video crews and production costs.
Then software firms such as krpano and Matterport came along. These are great software. Especially Matterport which made a name for it’s unique doll-house view for houses.
Well, even though these are amazing, they are complicated, takes a lot of time and costs a good amount of money.
Things got easier now, with plugins in WordPress doing the job. Plugins such as iPanorama and MV 360 have been introduced a couple of years back. These plugins created virtual tours out of 360 panoramic images. They saved a lot of time and money since they don’t even cost one third of the amount compared to software or video production.
Though these are great plugins, people still find it hard since the interfaces are pretty complicated and requires some patience to be able to create a proper virtual tour.
However, things got even better. With a good amount of research and long term development, the latest virtual tour creator plugin in WordPress, WPVR was introduced last December. This one grabbed the attention of many in no time.
WPVR – The latest Virtual Tour Creator on WordPress
WPVR is an amazing virtual tour creator in WordPress. You simply upload 360 panoramic images, and this plugin will turn it into an exclusive virtual tour.
You can add all the rooms of a house or different areas of a location as separate scenes, and add hotspots to click on, to get information or move to the next scene. Each scene can be viewed in a complete 360 view. You can look left, right, up or down, and zoom in and zoom out however you wish.
Hence you can create a complete virtual tour, where a person can freely navigate, get information, and explore without even taking an actual visit.
What Makes It Exclusive?
WPVR is different from other plugins in many ways that makes it so much better.
1. Super Easy User Interface
The main thing that WPVR focused on was to create an user interface that is suitable for everyone, whether an expert or a novice.
The developers of WPVR researched into VR and virtual tour creators for quite some time in trying to understand what was necessary.
The first thing that hit them was that VR is a complicated matter. If you are not an expert, then it gets difficult to configure a proper 360 virtual tour.
Hence the idea was to create an interface which is straightforward and easy to learn in a few minutes. With WPVR, it is possible to learn and create a virtual tour in a matter of 10 to 20 mins.
In order to create a virtual tour with WPVR, you simply follow a few sequential steps:
Name the tour
Create a scene by uploading image
Add hotspots where required
Once you are satisfied with your tour, publish the tour
Embed it on the webpage
Done. Now you can view your page and experience the tour.
So basically if you just have one scene, then you need as low as 5 steps to create a virtual tour. If you have more scenes, you simply need to repeat steps 2 and 3 once for every scene. That’s how simple it is.
The developers automated complex settings in the back-end, and the users simply need to configure the very basics to create a virtual tour.
2. Compatible And Easy to Customize
WPVR is compatible with all themes and works on both Classic Editor and Gutenberg block editor.
Once you publish a Tour, it generates a shortcode and an Id. The shortcode can be directly applied on a web page using Classic Editor and the virtual tour will be embedded. Also you can add height and width to the shortcode to resize it to your requirements.
For Gutenberg, the plugin creates a separate block type called WPVR, which you get to choose when adding a block. Here, on the block toolbar, you simply need to provide the Id, the height and the width you wish. And that’s it.
You do not need any coding or other embedding plugins to place the virtual tour on your site.
However, if you do know coding, you can customize the hotspot icons. You simply need to create a custom class in your theme style sheets. You can then provide that class name to the plugin and the hotspot icon will be changed to what you assigned.
3. Easy To Learn
The plugin developers, though they created an easy interface, they made sure you find no trouble in using it at all by providing detailed documentations and video tutorials.
The documentations provide complete step by step guide to create a proper virtual tour. On top of that, the video tutorials explain each and every aspect of the plugins.
Which means you do not need any experts to assist you; you already have the required instructions needed to create, customize and publish virtual tours.
However, in case you face any issues or confusions, you can rely on their support team to assist you.
As you can see, this plugin lets you create virtual tours with no complications and provide full support whenever you require.
Some Information About WPVR
RexTheme, the developers of WPVR, started since 2012. While providing great web development support to many, RexTheme developed several themes and plugins of great value.
The developers of RexTheme started looking into Virtual Reality since March of 2018. With that, they came across 360 panoramic image viewers and virtual tour creators in WordPress.
With much research, the developers managed to use three.js and WebGL to construct great virtual tours. However, it was pretty complicated.
With time, the team researched and learnt deep about the problems people face with other virtual tour creators.
They also tried to understand what was keeping people away from embracing virtual tours despite showing great interest in its possibilities. The answer was cost and complication.
Developers tried using the other virtual tour creators and was confused with so many options all at once. Apart from that, when they inquired about other software such as Matterport, it turned out that it would cost a lot of money in hiring experts.
Eventually, with substantial hard work from a team of 10, WPVR was developed. Removing all the complications and making it affordable, this plugin is bound to be the next most preferred tool to create virtual tours.
Some Benefits of Using Virtual Tours
Now that there is a tool to create virtual tours, let us see how virtual tours are helpful.
1. Best way to connect with visitors
People visiting your site will be able to experience the location in the best possible way. Rather than just looking at images, they will be able to explore the place as if it’s reality.
People will be able to connect and gain genuine interest in the location and may get more excited to visit in person.
2. Easier To Highlight A Place
Let’s say you own a personal Museum. If you create a virtual tour of certain zones of the Museum, people will be able to check out the relics and amazing history the Museum holds on your website and will get a glimpse of how it feels to visit your place.
You can place hotspots for people to hover to get the name, and historic information on clicking the relics. Thus people will understand the depth of originality the place holds and would probably wish to visit your Museum to see the other zones.
You can do the same for a house, theme park, hotel, office etc. People will be will be able to understand how special your place is and will be able to know facts and details at the same time.
3. Ideal For Creating Genuine Attraction For Several Businesses
Virtual Tours can boost few businesses with more potential customers.
For example, if realtors have virtual tours of homes for sale, buyers will be able to take a tour and develop a good deal of interest. Hence, a prospect calling will mostly likely mean that he/she feels the house suits him/her.
Same goes for a hotel. You can let potential customers explore the luxuries you will provide. Tourists will find it more influential in taking decisions to choose your hotel.
In fact, virtual tours will be beneficial for schools to attract more students, libraries to attract more readers, large estates to help people find their way around, theme parks to showcase the rides and also guide them with direction, and many more.
How To Get And Use WPVR?
As long as you have a WordPress website, it’s pretty easy to get WPVR.
You will find the plugin in the WordPress repository if you simply search for WPVR and look for the following:
Once you have installed and activated the plugin, you can simply follow the instructions in the plugin documentations which gives a detailed step by step guide with images and proper instructions for you to understand and create virtual tours easily.
Conclusion
WordPress has endless possibilities, and one step further towards its advancement is VR. Hence, WPVR is a great initiative that made it easy for people to use the latest technology in WordPress and with no hassle.
If you backed off in the past due to cost and complication, then it’s time you embrace virtual tours again. Use the latest virtual creator, WPVR, to create and experience amazing virtual tours.
Although modern iOS hardware is powerful enough to handle many intensive and complex tasks, the device could still feel unresponsive if you are not careful about how your app performs. In this article, we will look into five optimization tricks that will make your app feel more responsive.
1. Dequeue Reusable Cell
You’ve probably used tableView.dequeueReusableCell(withIdentifier:for:) inside tableView(_:cellForRowAt:) before. Ever wondered why you have to follow this awkward API, instead of just passing an array of cell in? Let’s go through the reasoning of this.
Say you have a table view with a thousand rows. Without using reusable cells, we would have to create a new cell for each row, like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Create a new cell whenever cellForRowAt is called.
let cell = UITableViewCell()
cell.textLabel?.text = "Cell (indexPath.row)"
return cell
}
As you might have thought, this will add a thousand cells to the device’s memory as you scroll to the bottom. Imagine what would happen if each cell contained a UIImageView and a lot of text: Loading them all at once could cause the app to run out of memory! Apart from that, every single cell would require new memory to be allocated during scrolling. If you scroll a table view quickly, a lot of small chunks of memory will be allocated on the fly, and this process will make the UI janky!
To resolve this, Apple has provided us with the dequeueReusableCell(withIdentifier:for:) method. Cell reuse works by placing the cell that is no longer visible on the screen into a queue, and when a new cell is about to be visible on the screen (say, the subsequent cell below as the user scrolls down), the table view will retrieve a cell from this queue and modify it in the cellForRowAt indexPath: method.
By using a queue to store cells, the table view doesn’t need to create a thousand cells. Instead, it needs just enough cells to cover the area of the table view.
By using dequeueReusableCell, we can reduce the memory used by the app and make it less prone to running out of memory!
2. Using A Launch Screen That Looks Like The Initial Screen
As mentioned in Apple’s Human Interface Guidelines (HIG), launch screens can be used to enhance the perception of an app’s responsiveness:
“It’s solely intended to enhance the perception of your app as quick to launch and immediately ready for use. Every app must supply a launch screen.”
It’s a common mistake to use a launch screen as a splash screen to show branding or to add a loading animation. Design the launch screen to be identical to the first screen of your app, as mentioned by Apple:
“Design a launch screen that’s nearly identical to the first screen of your app. If you include elements that look different when the app finishes launching, people can experience an unpleasant flash between the launch screen and the first screen of the app.
“The launch screen isn’t a branding opportunity. Don’t design an entry experience that looks like a splash screen or an “About” window. Don’t include logos or other branding elements unless they’re a static part of your app’s first screen.”
Using a launch screen for loading or branding purposes could slow down the time of first use and make the user feel that the app is sluggish.
When you start a new iOS project, a blank LaunchScreen.storyboard will be created. This screen will be shown to the user while the app loads the view controllers and layout.
To make your app feel faster, you can design the launch screen to be similar to the first screen (view controller) that will be shown to the user.
For example, the Safari app’s launch screen is similar to its first view :
The launch screen storyboard is like any other storyboard file, except that you can only use the standard UIKit classes, like UIViewController, UITabBarController, and UINavigationController. If you attempt to use any other custom subclasses (such as UserViewController), Xcode will notify you that using custom class names is prohibited.
Another thing to note is that UIActivityIndicatorView doesn’t animate when placed on the launch screen, because iOS will generate a static image from the launch screen storyboard and displays it to the user. (This is mentioned briefly in the WWDC 2014 presentation “Platforms State of the Union”, around 01:21:56.)
Apple’s HIG also advises us not to include text on our launch screen, because the launch screen is static, and you can’t localize text to cater to different languages.
State preservation and restoration allow the user to return to the exact same UI state from just before they left the app. Sometimes, due to insufficient memory, the operating system might need to remove your app from memory while the app is in the background, and the app might lose track of its last UI state if it is not preserved, possibly causing users to lose their work in progress!
In the multitasking screen, we can see a list of apps that have been put in the background. We might assume that these apps are still running in the background; in reality, some of these apps might get killed and restarted by the system due to the demands of memory. The app snapshots we see in the multitasking view are actually screenshots taken by the system from right when we exited the app (i.e. to go to the home or multitasking screen).
iOS uses these screenshots to give the illusion that the app is still running or is still displaying this particular view, whereas the app might have been already terminated or restarted in the background while still displaying the same screenshot.
Have you ever experienced, upon resuming an app from the multitasking screen, that the app shows a user interface different from the snapshot shown in the multitasking view? This is because the app hasn’t implemented the state-restoration mechanism, and the displayed data was lost when the app was killed in the background. This can lead to a bad experience because the user expects your app to be in the same state as when they left it.
“They expect your app to be in the same state as when they left it. State preservation and restoration ensures that your app returns to its previous state when it launches again.”
UIKit does a lot of work to simplify state preservation and restoration for us: It handles the saving and loading of an app’s state automatically at appropriate times. All we need to do is add some configuration to tell the app to support state preservation and restoration and to tell the app what data needs to be preserved.
To enable state saving and restoring, we can implement these two methods in AppDelegate.swift:
During state preservation, any view controller or view that has been assigned a restoration identifier will have its state saved to disk.
Restoration identifiers can be grouped together to form a restoration path. The identifiers are grouped using the view hierarchy, from the root view controller to the current active view controller. Suppose a MyViewController is embedded in a navigation controller, which is embedded in another tab bar controller. Assuming they are using their own class names as restoration identifiers, the restoration path will look like this:
When the user leaves the app with the MyViewController being the active view controller, this path will be saved by the app; then the app will remember the previous view hierarchy shown (Tab Bar Controller ? Navigation Controller ? My View Controller).
After assigning the restoration identifier, we will need to implement the encodeRestorableState(with coder:) and decodeRestorableState(with coder:) methods for each of the preserved view controllers. These two methods let us specify what data need to be saved or loaded and how to encode or decode them.
Let’s see the view controller:
// MyViewController.swift
// MARK: State restoration
// UIViewController already conforms to UIStateRestoring protocol by default
extension MyViewController {
// will be called during state preservation
override func encodeRestorableState(with coder: NSCoder) {
// encode the data you want to save during state preservation
coder.encode(self.username, forKey: "username")
super.encodeRestorableState(with: coder)
}
// will be called during state restoration
override func decodeRestorableState(with coder: NSCoder) {
// decode the data saved and load it during state restoration
if let restoredUsername = coder.decodeObject(forKey: "username") as? String {
self.username = restoredUsername
}
super.decodeRestorableState(with: coder)
}
}
Remember to call the superclass implementation at the bottom of your own method. This ensures that the parent class has a chance to save and restore state.
Once the objects have finished decoding, applicationFinishedRestoringState() will be called to tell the view controller that the state has been restored. We can update the UI for the view controller in this method.
// MyViewController.swift
// MARK: State restoration
// UIViewController already conforms to UIStateRestoring protocol by default
extension MyViewController {
...
override func applicationFinishedRestoringState() {
// update the UI here
self.usernameLabel.text = self.username
}
}
There you have it! These are the essential methods to implement state preservation and restoration for your app. Keep in mind that the operating system will remove the saved state when the app is being force-closed by the user, in order to avoid getting stuck in a broken state in case something goes wrong in the state preservation and restoration.
Also, don’t store any model data (i.e. data that should have been saved to UserDefaults or Core Data) to the state, even though it might seem convenient to do so. State data will be removed when the user force quits your app, and you certainly don’t want to lose model data this way.
To test whether state preservation and restoration are working well, follow the steps below:
Build and launch an app using Xcode.
Navigate to the screen with state preservation and restoration that you want to test.
Return to the home screen (by swiping up or double-clicking home button, or pressing Shift ? + Cmd ? + H in the simulator) to send the app to the background.
Stop the app in Xcode by pressing the ? button.
Launch the app again and check whether the state has been restored successfully.
Because this section only covers the basics of state preservation and restoration, I recommend the following articles by Apple Inc. for more in-depth knowledge of state restoration:
4. Reduce Usage Of Non-Opaque Views As Much As Possible
An opaque view is a view that has no transparency, meaning that any UI element placed behind it is not visible at all. We can set a view to be opaque in the Interface Builder:
Or we can do it programmatically with the isOpaque property of UIView:
view.isOpaque = true
Setting a view to opaque will make the drawing system optimize some drawing performance while rendering the screen.
If a view has transparency (i.e. alpha is below 1.0), then iOS will have to do extra work to calculate what should be displayed by blending different layers of views in the view hierarchy. On the other hand, if a view is set to opaque, then the drawing system will just put this view in front and avoid the extra work of blending the multiple view layers behind it.
You can check which layers are being blended (non-opaque) in the iOS Simulator by checking Debug ? Color Blended Layers.
After checking the Color Blended Layers option, you can see that some views are red and some are green. Red indicates that the view is not opaque and that its output display is a result of layers blended behind it. Green indicates that the view is opaque and no blending has been done.
The labels shown above (“View Friends”, etc.) are highlighted in red because when a label is dragged to the storyboard, its background color is set to transparent by default. When the drawing system is compositing the display near the label area, it will ask for the layer behind the label and do some calculation.
One way you can optimize app performance is to reduce how many views are highlighted with red as much as possible.
By changing label.backgroundColor = UIColor.clear to label.backgroundColor = UIColor.white, we can reduce layer blending between the label and the view layer behind it.
You might have noticed that, even if you have set a UIImageView to opaque and assigned a background color to it, the simulator will still show red in the image view. This is probably because the image you used for the image view has an alpha channel.
To remove the alpha channel for an image, you can use the Preview app to make a duplicate of the image (Shift ? + Cmd ? + S), and uncheck the “Alpha” checkbox when saving.
5. Pass Heavy Processing Functions To Background Threads (GCD)
Because UIKit only works on the main thread, performing heavy processing on the main thread will slow down the UI. The main thread is used by UIKit not only to handle and respond to user input, and also to draw the screen.
The key to making an app responsive is to move as many heavy processing tasks to background threads as possible. Avoid doing complex calculation, networking, and heavy IO operation (e.g. reading and writing to disk) on the main thread.
You might have once used an app that suddenly became unresponsive to your touch input, and it feels like the app has hung. This is most probably caused by the app running heavy computation tasks on the main thread.
The main thread usually alternates between UIKit tasks (such as handling user input) and some light tasks in small intervals. If a heavy task is running on main thread, then UIKit will need to wait until the heavy task has finished before being able to handle touch input.
By default, the code inside view controller lifecycle methods (such as viewDidLoad) and IBOutlet functions are executed on the main thread. To move heavy processing tasks to a background thread, we can use the Grand Central Dispatch queues provided by Apple.
Here’s the template for switching queues :
// Switch to background thread to perform heavy task.
DispatchQueue.global(qos: .default).async {
// Perform heavy task here.
// Switch back to main thread to perform UI-related task.
DispatchQueue.main.async {
// Update UI.
}
}
The qos stands for “quality of service”. Different quality-of-service values indicate different priorities for the specified tasks. The operating system will allocate more CPU time and CPU power I/O throughput for tasks allocated in queues with higher QoS values, meaning that a task will finish faster in a queue with higher QoS values. A higher QoS value will also consume more energy due to it using more resources.
Here is the list of QoS values from highest to lowest priority:
Apple has provided a handy table with examples of which QoS values to use for different tasks.
One thing to keep in mind is that all UIKit code should always be executed on the main thread. Modifying UIKit objects (such as UILabel and UIImageView) on the background thread could have an unintended consequence, like the UI not actually updating, a crash occurring, and so on.
“Updating UI on a thread other than the main thread is a common mistake that can result in missed UI updates, visual defects, data corruptions, and crashes.”
The trade-off of performance optimization is that you have to write more code or configure additional settings on top of the app’s functionality. This might make your app delivered later than expected, and you will have more code to maintain in the future, and more code means potentially more bugs.
Before spending time on optimizing your app, ask yourself whether the app is already smooth or whether it has some unresponsive part that really needs to be optimized. Spending a lot of time optimizing an already smooth app to shave off 0.01 seconds might not be worth it, as the time could be better spent developing better features or other priorities.
Not to be confused with Lifecycle Hooks, Hooks were introduced in React in v16.7.0-alpha, and a proof of concept was released for Vue a few days after. Even though it was proposed by React, it’s actually an important composition mechanism that has benefits across JavaScript framework ecosystems, so we’ll spend a little time today discussing what this means.
Mainly, Hooks offer a more explicit way to think of reusable patterns — one that avoids rewrites to the components themselves and allows disparate pieces of the stateful logic to seamlessly work together.
The initial problem
In terms of React, the problem was this: classes were the most common form of components when expressing the concept of state. Stateless functional components were also quite popular, but due to the fact that they could only really render, their use was limited to presentational tasks.
Classes in and of themselves present some issues. For example, as React became more ubiquitous, stumbling blocks for newcomers did as well. In order to understand React, one had to understand classes, too. Binding made code verbose and thus less legible, and an understanding of this in JavaScript was required. There are also some optimization stumbling blocks that classes present, discussed here.
In terms of the reuse of logic, it was common to use patterns like render props and higher-order components, but we’d find ourselves in similar “pyramid of doom” — style implementation hell where nesting became so heavily over-utilized that components could be difficult to maintain. This led me to ranting drunkenly at Dan Abramov, and nobody wants that.
Hooks address these concerns by allowing us to define a component’s stateful logic using only function calls. These function calls become more compose-able, reusable, and allows us to express composition in functions while still accessing and maintaining state. When hooks were announced in React, people were excited — you can see some of the benefits illustrated here, with regards to how they reduce code and repetition:
In terms of maintenance, simplicity is key, and Hooks provide a single, functional way of approaching shared logic with the potential for a smaller amount of code.
Why Hooks in Vue?
You may read through this and wonder what Hooks have to offer in Vue. It seems like a problem that doesn’t need solving. After all, Vue doesn’t predominantly use classes. Vue offers stateless functional components (should you need them), but why would we need to carry state in a functional component? We have mixins for composition where we can reuse the same logic for multiple components. Problem solved.
I thought the same thing, but after talking to Evan You, he pointed out a major use case I missed: mixins can’t consume and use state from one to another, but Hooks can. This means that if we need chain encapsulated logic, it’s now possible with Hooks.
Hooks achieve what mixins do, but avoid two main problems that come with mixins:
They allows us to pass state from one to the other.
They make it explicit where logic is coming from.
If we’re using more than one mixin, it’s not clear which property was provided by which mixin. With Hooks, the return value of the function documents the value being consumed.
So, how does that work in Vue? We mentioned before that, when working with Hooks, logic is expressed in function calls that become reusable. In Vue, this means that we can group a data call, a method call, or a computed call into another custom function, and make them freely compose-able. Data, methods, and computed now become available in functional components.
Example
Let’s go over a really simple hook so that we can understand the building blocks before we move on to an example of composition in Hooks.
useWat?
OK, here’s were we have, what you might call, a crossover event between React and Vue. The use prefix is a React convention, so if you look up Hooks in React, you’ll find things like useState, useEffect, etc. More info here.
In Evan’s live demo, you can see where he’s accessing useState and useEffect for a render function.
If you’re not familiar with render functions in Vue, it might be helpful to take a peek at that.
But when we’re working with Vue-style Hooks, we’ll have — you guessed it — things like: useData, useComputed, etc.
So, in order for us look at how we’d use Hooks in Vue, I created a sample app for us to explore.
In the src/hooks folder, I’ve created a hook that prevents scrolling on a useMounted hook and reenables it on useDestroyed. This helps me pause the page when we’re opening a dialog to view content, and allows scrolling again when we’re done viewing the dialog. This is good functionality to abstract because it would probably be useful several times throughout an application.
import { useDestroyed, useMounted } from "vue-hooks";
export function preventscroll() {
const preventDefault = (e) => {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
// keycodes for left, up, right, down
const keys = { 37: 1, 38: 1, 39: 1, 40: 1 };
const preventDefaultForScrollKeys = (e) => {
if (keys[e.keyCode]) {
preventDefault(e);
return false;
}
}
useMounted(() => {
if (window.addEventListener) // older FF
window.addEventListener('DOMMouseScroll', preventDefault, false);
window.onwheel = preventDefault; // modern standard
window.onmousewheel = document.onmousewheel = preventDefault; // older browsers, IE
window.touchmove = preventDefault; // mobile
window.touchstart = preventDefault; // mobile
document.onkeydown = preventDefaultForScrollKeys;
});
useDestroyed(() => {
if (window.removeEventListener)
window.removeEventListener('DOMMouseScroll', preventDefault, false);
//firefox
window.addEventListener('DOMMouseScroll', (e) => {
e.stopPropagation();
}, true);
window.onmousewheel = document.onmousewheel = null;
window.onwheel = null;
window.touchmove = null;
window.touchstart = null;
document.onkeydown = null;
});
}
And then we can call it in a Vue component like this, in AppDetails.vue:
We’re using it in that component, but now we can use the same functionality throughout the application!
Two Hooks, understanding each other
We mentioned before that one of the primary differences between hooks and mixins is that hooks can actually pass values from one to another. Let’s look at that with a simple, albeit slightly contrived, example.
Let’s say in our application we need to do calculations in one hook that will be reused elsewhere, and something else that needs to use that calculation. In our example, we have a hook that takes the window width and passes it into an animation to let it know to only fire when we’re on larger screens.
In the first hook:
import { useData, useMounted } from 'vue-hooks';
export function windowwidth() {
const data = useData({
width: 0
})
useMounted(() => {
data.width = window.innerWidth
})
// this is something we can consume with the other hook
return {
data
}
}
Then, in the second we use this to create a conditional that fires the animation logic:
// the data comes from the other hook
export function logolettering(data) {
useMounted(function () {
// this is the width that we stored in data from the previous hook
if (data.data.width > 1200) {
// we can use refs if they are called in the useMounted hook
const logoname = this.$refs.logoname;
Splitting({ target: logoname, by: "chars" });
TweenMax.staggerFromTo(".char", 5,
{
opacity: 0,
transformOrigin: "50% 50% -30px",
cycle: {
color: ["red", "purple", "teal"],
rotationY(i) {
return i * 50
}
}
},
...
Then, in the component itself, we’ll pass one into the other:
Now we can compose logic with Hooks throughout our application! Again, this is a contrived example for the purposes of demonstration, but you can see how useful this might be for large scale applications to keep things in smaller, reusable functions.
Future plans
Vue Hooks are already available to use today with Vue 2.x, but are still experimental. We’re planning on integrating Hooks into Vue 3, but will likely deviate from React’s API in our own implementation. We find React Hooks to be very inspiring and are thinking about how to introduce its benefits to Vue developers. We want to do it in a way that complements Vue’s idiomatic usage, so there’s still a lot of experimentation to do.
You can get started by checking out the repo here. Hooks will likely become a replacement for mixins, so although the feature still in its early stages, it’s probably a concept that would be beneficial to explore in the meantime.
(Sincere thanks to Evan You and Dan Abramov for proofing this article.)
I rather like position: sticky;. It has practical use cases. I think of things like keeping a table of contents in a sidebar of a long article, but as a fairly simple implementation and without risk of overlapping things in awkward ways. But Elad Shechter is right here: it’s not used that much — at least partially — and probably because it’s a bit weird to understand.
I like how Elad explains it with a “Sticky Item” and a “Sticky Container.” The container needs to be large enough that scrolling is relevant and for the stickiness to do anything at all.
There are other gotchas, too. I feel like every time I try position: sticky; in a real context, I have about a 30% chance of it working. There always seems to be some parent/child relationship thing that I can’t quite work out to prevent overlaps. Or, there is some parent element with overflow: hidden;, which, for reasons unbeknownst to me, breaks this.
Within the world of the internet, there are many great things. You can order food, shop in your underwear, and connect with people from all over the world right from your living room. Unfortunately, with these amazing things comes some pretty terrible things, too. Today, we’re going to be focusing on some of the worst design fails ever, and how you can avoid them.
Some of these fails are generic, and will have specific examples. Regardless of which category each one falls into, the point of this list is to avoid each and every one of the following fails completely. After all, that’s why they call it a fail.
Overdesign
Over designed websites are the worst thing to happen to any website. Fortunately, these websites are being weeded out slowly, but they definitely still exist, and they’re still pretty terrible.
The reasons to avoid such a terrible decision are pretty obvious. For one, too much on one page can greatly slow down your loading speeds, and it sends the reader away almost immediately. Secondly, it confuses everyone. Looking at the image above, if you manage not to get a headache and pass out, you’ll have a hard time finding what you’re looking for.
Granted, web design isn’t always easy. After all, if it were easy, we wouldn’t have a need for web designers at all. The moral of this story is to make it simple, make it clean, and for the love of God, make it easy to navigate.
Auto-playing audio and video
We’ve all been there. It’s late, you’re tired, you’re just ready to go to bed, and out of nowhere, amongst your dozens of tabs you have opened, a video starts playing. Now, you get to play the always fun and engaging game of “guess the tab” and try your best to shut down the video. It feels like you’re trying to defuse a bomb. Only in this case, you don’t know where the bomb is and you feel like crying.
If ever you find yourself wondering if an auto-playing video or audio file anywhere within your web design, stop yourself. Unless you want to slow your loading times down, and make literally everyone on the internet upset, avoid this design fail.
Websites that aren’t mobile friendly
We live in a time where everyone uses their phone for just about everything. Even if they aren’t dependant on their phones, they use them at least a few times a day. The way the web is evolving means that more and more people will be using their phones for tasks that used to be impossible using mobile web browsers. It should be a crime to not at least think about mobile users when designing a website.
Each year, the amount of mobile users goes up by a healthy amount. In fact, as of the start of 2019, over 63% of internet users are on mobile devices. Pretty soon, mobile users might make up most, if not all of your visitors. With that in mind, it’s absolutely worth spending some time to avoid this design fail, and making your website mobile friendly.
Sidebars
As helpful as sidebars used to be, and arguably still are, they’re just not good looking. Most of the time, the sidebar takes up a good portion of your main interface, and it gets quite distracting. Call it a trend if you want, but major websites like Amazon and Ebay have ditched the sidebar for a more streamlined look.
The idea is to have your visitors interact with your website. As easy as it would be to just throw up a sidebar and have all the navigation options users might need right in front of them, it takes away from the experience.
Passive-aggressive CTAs
Listen, I love conversions as much as the next guy, but being passive-aggressive about a CTA is a very quick way to turn a potential customer away completely. It might seem like a good idea, but using a CTA like, “No thanks, I don’t want to grow my traffic” actually comes off as desperate on your part, not the potential customer.
I think the overall theme of this article, aside from design fails, is to stop and think before you act. Think about how you would react in your visitors’ shoes. If you can honestly say that you wouldn’t like it, then odds are that your visitors won’t, either. A passive-aggressive CTA is a great example of this analogy, but being passive-aggressive in general works here, too. Stop, and try a different approach.
Trying to keep up with all the trends
Trends are important in any type of design. In fact, keeping up with trends should be the main objective of any designer, whether it’s web, interior, clothing, or anything else. So why, you may ask, is it such a bad thing to keep up with many trends at once? The short answer is that it takes the focus off of the content of the website.
Yes, using a color gradient is cool, and encouraged. Maybe even a few custom doodles to bring your website to life and give it a unique look. What’s not encouraged is pumping your website full of so many trends that it looks like the front cover of The Cosmopolitan. You’ll end up misdirecting your visitors. Keep it simple, and focus on the content. If the content of your website is quality, then the rest of your site will follow suit with little to no effort from you.
The conclusion
When you really take a look, design fails are everywhere, and they always will be. To be fair, there is a place for design fails on the internet. They give us opportunities to learn, and in a way, they make good design stand out more.
Of course, this is just a small list of design fails to avoid. There are many more out there that you should try your best to avoid. And, as important as it is to stay up-to-date with web design trends, perhaps the worst mistake any of us could make is using too many. Web design is all about balance. You find that balance, and you, my friend, have found the keys to success.
We will never live in a world where everyone viewing our sites has an identical browser and browser version, just as we will never live in a world where everyone has the same size screen and resolution. This means that dealing with old browsers — or browsers which do not support something that we want to use — is part of the job of a web developer. That said, things are far better now than in the past, and in this article, I’m going to have a look at the different types of browser support issues we might run into. I’m going to show you some ways to deal with them, and also look at things which might be coming soon which can help.
Why Do We Have These Differences?
Even in a world where the majority of browsers are Chromium-based, those browsers are not all running the same version of Chromium as Google Chrome. This means that a Chromium-based browser such as Vivaldi, might be a few versions behind Google Chrome.
And, of course, users do not always quickly update their browsers, although that situation has improved in recent years with most browsers silently upgrading themselves.
There is also the manner in which new features get into browsers in the first place. It is not the case that new features for CSS are designed by the CSS Working Group, and a complete spec handed down to browser vendors with an instruction to implement it. Quite often it is only when an experimental implementation happens, that all the finer details of the specification can be worked out. Therefore, feature development is an iterative process and requires that browsers implement these specifications in development. While implementation happens these days most often behind a flag in the browser or available only in a Nightly or preview version, once a browser has a complete feature, it is likely to switch it on for everyone even if no other browser yet has support.
All this means that — as much as we might like it — we will never exist in a world where features are magically available on every desktop and phone simultaneously. If you are a professional web developer then your job is to deal with that fact.
Bugs vs. Lack Of Support
There are three issues that we face with regard to browser support:
No Support Of A Feature The first issue (and easiest to deal with) is when a browser does not support the feature at all.
Dealing With Browser “Bugs” The second is when the browser claims to support the feature, but does so in a way that is different to the way that other browsers support the feature. Such an issue is what we tend to refer to as a “browser bug” because the end result is inconsistent behavior.
Partial Support Of CSS Properties This one is becoming more common; a situation in which a browser supports a feature — but only in one context.
It’s helpful to understand what you are dealing with when you see a difference between browsers, so let’s have a look at each of these issues in turn.
1. No Support Of A Feature
If you use a CSS property or value that a browser does not understand, the browser will ignore it. This is the same whether you use a feature that is unsupported, or make up a feature and try to use it. If the browser does not understand that line of CSS, it just skips it and gets on with the next thing it does understand.
This design principle of CSS means that you can cheerfully use new features, in the knowledge that nothing bad will happen to a browser that doesn’t have support. For some CSS, used purely as an enhancement, that is all you need to do. Use the feature, make sure that when that feature is not available the experience is still good, and that’s it. This approach is the basic idea behind progressive enhancement, using this feature of the platform which enables the safe use of new things in browsers which don’t understand them.
If you want to check whether a feature you are using is supported by browsers then you can look at the Can I Use website. Another good place to look for fine-grained support information is the page for each CSS property on MDN. The browser support data there tends to be very detailed.
New CSS Understands Old CSS
As new CSS features are developed, care is taken in terms of how they interact with existing CSS. For example, in the Grid and Flexbox specification, it is detailed in terms of how display: grid and display: flex deal with scenarios such as when a floated item becomes a grid item, or a multicol container is turned into a grid. This means that certain behaviors are ignored, helping you to simply overwrite the CSS for the nonsupporting browser. These overrides are detailed in the page for Progressive enhancement and Grid Layout on MDN.
Detecting Support With Feature Queries
The above method only works if the CSS you need to use does not need other properties to go along with it. You might need to add additional properties to your CSS for older browsers which would then also be interpreted by the browsers which support the feature too.
A good example of this can be found when using Grid Layout. While a floated item which becomes a grid item loses all float behavior, it is likely that if you are trying to create a fallback for a grid layout with float, you will have added percentage widths and possibly margins to the items.
.grid > .item {
width: 23%;
margin: 0 1%;
}
These widths and margins will then still apply when the floated item is a grid item. The width becomes a percentage of the grid track rather than the full width of the container; any margin will then be applied as well as a gap you may have specified.
Thankfully, there is a feature built into CSS and implemented into modern browsers which helps us deal with this situation. Feature Queries allow us to directly ask the browser what they support and then act on the response. Just like a Media Query — which tests for some properties of the device or screen — Feature Queries test for support of a CSS property and value.
Test For Support
Testing for support is the simplest case, we use @supports and then test for a CSS property and value. The content inside the Feature Query will only run if the browser responds with true, i.e. it does support the feature.
Test For No Support
You can ask the browser if it does not support a feature. In this case, the code inside the Feature Query will only run if the browser indicates it has no support.
@supports not (display: grid) {
.item {
/* CSS from browsers which do not support grid layout */
}
}
Test For Multiple Things
If you need more than one property to be supported, use and.
@supports (display: grid) and (shape-outside: circle()){
.item {
/* CSS from browsers which support grid and CSS shapes */
}
}
If you need support of one property or another, use or.
@supports (display: grid) or (display: flex){
.item {
/* CSS from browsers which support grid or flexbox */
}
}
Picking A Property And Value To Test For
You don’t need to test for every property you want to use — just something which would indicate support for the features you are planning to use. Therefore, if you want to use Grid Layout, you might test for display: grid. In the future (and once subgrid support lands in browsers), you might need to be more specific and test for subgrid functionality. In that case, you would test for grid-template-columns: subgrid to get a true response from only those browsers which had implemented subgrid support.
If we now return to our floated fallback example, we can see how feature queries will sort it out for us. What we need to do is to query the browser to find out if it supports grid layout. If it does, we can set the width on the item back to auto and the margin to 0.
Note that while I have included all of the grid code inside my feature query, I don’t need to. If a browser didn’t understand the grid properties it would ignore them so they could safely be outside of the feature query. The things that must be inside a feature query in this example are the margin and width properties, as these are needed for the old browser code but would also be applied by supporting browsers.
Embrace The Cascade
A very simple way to offer fallbacks is to utilize the fact that browsers ignore CSS that they don’t understand, and the fact that where everything else has equal specificity, source order is taken into account in terms of which CSS is applied to an element.
You first write your CSS for browsers which do not support the feature. Then test for support of property you want to use, if the browser confirms it has support overwrite the fallback code with your new code.
This is pretty much the same procedure that you might use when using media queries for responsive design, following a mobile-first approach. In that approach, you start with your layout for smaller screens, then add or overwrite things for larger ones as you move up through your breakpoints.
The above way of working means that you do not need to worry about browsers which do not support Feature Queries. As you can see from Can I Use, Feature Queries have really great support. The standout browsers that do not support them being any version of Internet Explorer.
It is likely, however, that the new feature you want to use is also not supported in IE. So, at the present time you will almost always start by writing CSS for browsers without support, then you test with a Feature Query. This Feature Query should test for support.
Browsers which support Feature Queries will return true if they have support and so the code inside the query will be used, overwriting the code for older browsers.
If the browser supports Feature Queries but not the feature being tested, it will return false. The code inside the feature query will be ignored.
If the browser does not support Feature Queries then everything inside the Feature Query block will be ignored, which means that a browser such as IE11 will use your old browser code, which is very likely exactly what you want!
2. Dealing With Browser “Bugs”
The second browser support issue is thankfully becoming less common. If you read “What We Wished For” (published at the end of last year), you can get a little tour into some of the more baffling browser bugs of the past. That said, any software is liable to have bugs, browsers are no exception. And, if we add to that the fact that due to the circular nature of specification implementation, sometimes a browser implemented something and then the spec changed so they now need to issue an update. Until that update ships, we might be in a situation where browsers do something different to each other.
Feature Queries can’t help us if the browser reports support of something supports it badly. There is no mode by which the browser can say, “Yes, but you probably won’t like it.” When an actual interoperability bug shows up, it is in these situations where you might need to be a little more creative.
If you think you are seeing a bug then the first thing to do is confirm that. Sometimes when we think we see buggy behavior, and browsers doing different things, the fault lies with us. Perhaps we have used some invalid syntax, or are trying to style malformed HTML. In those cases, the browser will try to do something; however, because you aren’t using the languages as they were designed, each browser might cope in a different way. A quick check that your HTML and CSS is valid is an excellent first step.
At that point, I’d probably do a quick search and see if my issue was already widely understood. There are some repos of known issues, e.g. Flexbugs and Gridbugs. However, even just a well-chosen few keywords can turn up Stack Overflow posts or articles that cover the subject and may hand you a workaround.
But let’s say you don’t really know what is causing the bug, which makes it pretty hard to search for a solution. So, the next step is to create a reduced test case of your issue, i.e. stripping out anything irrelevant to help you identify exactly what triggers the bug. If you think you have a CSS bug, can you remove any JavaScript, or recreate the same styling outside of a framework? I often use CodePen to pop together a reduced test case of something I am seeing; this has the added advantage of giving me the code in a way I can easily share with someone else if I need to ask about it.
Most of the time, once you have isolated the issue, it is possible to think up an alternate way of achieving your desired result. You will find that someone else has come up with a cunning workaround, or you can post somewhere to ask for suggestions.
With that said, if you think you have a browser bug and can’t find anyone else talking about the same issue, it is quite possible you have found something new that should be reported. With all of the new CSS that has landed recently, issues can sometimes show up as people start to use things in combination with other parts of CSS.
Check out this post from Lea Verou about reporting such issues, “Help The Community! Report Browser Bugs!”. The article also has great tips for creating a reduced test case.
3. Partial Support Of CSS Properties
The third type of issue has become more common due to the way that modern CSS specifications are designed. If we think about Grid Layout and Flexbox, these specs both use the properties and values in Box Alignment Level 3, to do alignment. Therefore, properties such as align-items, justify-content, and column-gap are specified to be used in both Grid and Flexbox as well as other layout methods.
At the time of writing, however, the gap properties work in Grid Layout in all grid-supporting browsers, and column-gap works in Multicol; however, only Firefox has implemented these properties for Flexbox.
If I were to use margins to create a fallback for Flexbox, then test for column-gap and remove the margins, my boxes will have no space between them in browsers which support column-gap in Grid or multicol, so my fallback spacing will be removed.
@supports(column-gap: 20px) {
.flex {
margin: 0; /* almost everything supports column-gap so this will always remove the margins, even if we do not have gap support in flexbox. */
}
}
This is a current limitation of Feature Queries. We don’t have a way to test for support of a feature in another feature. In the above situation, what I want to ask the browser is, “Do you have support for column-gap in Flexbox?” This way, I can get a negative response so I can use my fallback.
There is a similar issue with the CSS fragmentation properties break-before, break-after, and break-inside. As these have better support when the page is printed, browsers will often claim support. However, if you are testing for support in multicol, you get what appear to be false positives. I’ve raised an issue over at the CSS Working Group for this issue, however, it isn’t a straightforward problem to solve. If you have thoughts, please do add them there.
Testing For Selector Support
Currently, Feature Queries can only test for CSS Properties and Values. Another thing we might like to test for is the support of newer selectors, such as those in Level 4 of the Selectors specification. There is an explainer note and also an implementation behind a flag in Firefox Nightly of a new feature for Feature Queries which will achieve this.
If you visit about:config in Firefox and enable the flag layout.css.supports-selector.enabled then you can test to see if various selectors are supported. The syntax is currently very straightforward, for example to test for the :has selector:
@supports selector(:has){
.item {
/* CSS for support of :has */
}
}
This is a specification in development, however, you can see how features to help us manage the ever-present issues of browser support are being added as we speak.
Further Reading
It can seem frustrating when you want to use a feature and discover that it isn’t supported by one major browser, or if things seem to be behaving in different ways. I’ve rounded up some practical further reading that might help.