Visual Project Management for Teams
More than 10,000 teams already get organized with Dapulse, the next generation visual project management tool.
More than 10,000 teams already get organized with Dapulse, the next generation visual project management tool.
Do you ever wish you had a time machine? I certainly do, but not for the usual reasons. I want a time machine so I can go back and have a frank conversation with my younger self. I’ll let you in on a bit of a secret: My younger self was an idiot!
I have been working on the web for over 22 years now, and I feel like I wasted so many of those years. If only I could go back and share a few hard truths with myself at the start of my career. Unfortunately, I cannot, but I can share that advice with you.
Admittedly, you are almost certainly not as idiotic as I was. But hopefully, there will be something in this advice that inspires you.
Speaking of inspiration, that leads me nicely into my first piece of wisdom!
I used to be a dedicated follower of fashion who wasted so much time looking at other “cool” websites and browsing galleries of inspirational websites. My design style would morph to embrace the latest trends, from Web 2.0 to hero banners.
The result of this was bland “me too” design. But worst of all, it never put the user first. It was all about making something look good in my portfolio.
It was such a waste because so much inspiration is all around us: great books on classic print design, architectural trends, even airport signage (a personal obsession of mine).
Don’t make my mistakes. You don’t even have the luxury of my excuses. With CSS grid3, the possibilities are endless, and we should all embrace them.
On the subject of latest trends, that brings me to my next transgression: obsessing over tools.
We’ve wasted hours arguing over what tool is best. Should we code in PHP or classic ASP? (Yes, I am that old.) Can I be a “proper” web designer and code in Dreamweaver? Which content management systems should we use? The list went on.
Some tool or other would become trendy for whatever reason, and we would all jump on the bandwagon, until the next one emerged, and we jumped to that after an even more furious debate.
I see the same today: arguments over frameworks4 and whether we should embrace Angular or React. I don’t follow these discussions anymore because somewhere along the line I realized something: There is no single answer.
5A lot of these choices come down to personal preference or the requirements of the individual client. Remain flexible and open to change. If you don’t, you’ll go the way of Flash developers.
All of that time I wasted arguing about tools would have been so much better spent elsewhere, like on improving my soft skills.
I was an insufferable know-it-all when I was young. I always had the answers and always knew a better way to do something. I am sure you are not like that, although, let’s be honest, how would you know if you were? I certainly had no idea how irritating I was, despite the warning signs.
For a start, I found myself constantly arguing with everybody. Everything seemed like a battle because nobody around me “got it.” In hindsight, that was because I was too busy irritating everybody to take the time to explain things properly. But at the time, it just felt like everybody else was stupid.
I wish I had realized how weak I was in this area. Perhaps then I would have invested time and energy in improving how I worked alongside other people. Maybe I would have listened more and put the same effort into understanding my colleagues as I did my users.
I am not suggesting I should have done this necessarily to be a good man (trust me, I am not now). Instead, I should have done this because it would have made my life so much easier. I wasted endless time arguing and alienating people, people I needed on my side to do my job. It was incredibly frustrating.
7If I had developed that skill of working with people earlier, it would have also allowed me to push beyond the confines of my role.
I confess that, for many years, I was a bit of a job’s worth. I was a designer, and I spent much of my working life complaining because other people weren’t doing their jobs properly. Clients failed to deliver copy, developers didn’t implement my designs correctly, and project managers were always putting unrealistic constraints on me.
To be fair to my younger self, these were all real problems. But I did nothing but moan about them. I made no effort to help my colleagues fix these issues. I never questioned why the client was failing to deliver content or why the project manager seemed so unreasonable? I didn’t bother to understand the constraints they faced.
When I did eventually wake up and start paying attention, I discovered a bigger world. I found out just how interconnected digital and the user experience are, and how many things beyond the screen influence the experience.
I learned so much over that time, and you can, too. Take the time to understand the roles of those around you. Understand their challenges and constraints. Understand their perspectives and motivations. This will not only improve your working relationship, but make you better at your job, too.
9If you are a designer, this will enhance your designs, making them more useful in the “real world.” If you are a developer, you will understand the challenges users face and the impact you have on the user experience11. And so it goes on.
Ultimately, this will make you better at your job and hopefully progress your career. But a successful career is about more than being good at your job.
You could be the best designer or developer in the world, but if nobody has heard of you, you will have little success. That probably isn’t right or fair, but that is the reality.
I’ll be honest with you: Many people are far better at their jobs than me. But I speak all around the world, write books and have built a significant following, not because I am good at what I do, but because I put myself out there.
But it took me so long to realize that. I wasted years moaning about how it was unfair that other people got to write and speak and how my ideas were just as good as theirs.
Eventually, it twigged that I didn’t need anybody’s permission to start sharing my thoughts. I could write on a blog without a publisher and speak on a podcast without a conference.
You can, too. Not only that, you should! If you are not sharing what you have learned, you are invisible, and that will hamper your career.
12You might feel you have nothing new to say. Don’t worry, just share what you have learned. There will always be people who haven’t learned those lessons yet.
You might feel nobody is listening. Again, don’t worry. If you persevere, eventually people will start paying attention. I’ll let you in on a secret: Quality is not the number one reason for success. Consistency is. Even second-rate content will draw attention if you release it regularly enough.
Put yourself out there, in whatever way you choose. It will enable you to build contacts in the industry. That will help you avoid the last mistake my younger self-made: wasting too many years working for appalling bosses.
I worked for some truly nasty people, ranging from the incompetent to the criminal. Two ended up in prison, and the only good guy I ever worked for died of a heart attack due to stress!
I wasted years working for these people, years of them undervaluing my work and failing to invest in enabling me to do it better. Admittedly, I could be a bit of an idiot, as we have already established. But even with hindsight, these people were terrible. Unfortunately, apathy and fear prevented me from moving on.
Don’t make my mistake. There is no need. We are much in demand. Getting good digital staff is incredibly challenging, and you owe no loyalty to a boss who doesn’t value your expertise.
Instead, find a company that is going to nurture you and help you grow in your career. I’ll be honest: I never achieved that. I never had a mentor or somebody to teach me. I stumbled my way through my career, and I think I am the poorer for it. So, don’t settle. You deserve better, and loads of great jobs are out there.
(al)
In these politically uncertain times, developers can help to defend their users’ personal privacy by adopting the Privacy by Design (PbD) framework. These common-sense steps will become a requirement under the EU’s imminent data protection overhaul, but the benefits of the framework go far beyond legal compliance.
Note: This article is not legal advice and should not be construed as such.
Let’s give credit where credit is due. The global political upheaval of the past 12 months has done more to get developers thinking about privacy, surveillance and defensive user protection than ever before. The risks and threats to ourselves, and to our users, are no longer theoretical; they are real, they are everyday, and they are frightening. One need only look at the ongoing revelations regarding Cambridge Analytica, a British company with odd links to Canada, which ran a complex data-mining operation on behalf of Donald Trump’s presidential campaign to aggregate up to 5,000 pieces of data on every American adult1, to fathom what is at stake for all of us.
As developers and decision-makers, we need to do something to respond to that challenge. The political uncertainty we are living through obliges us to change the ways we approach our work. As the creators of applications and the data flows they create, we can play a critical and positive role in protecting our users from attacks on their privacy, their dignity, and even their safety.
One way we can do this is by adopting a privacy-first best-practice framework. This framework, known as Privacy by Design (PbD), is about anticipating, managing and preventing privacy issues before a single line of code is written. The best way to mitigate privacy risks, according to the PbD philosophy, is not to create them in the first place.
PbD has existed as a best-practice framework since the 1990s, but few developers are aware of it, let alone use it. That’s about to change. The EU’s data protection overhaul, GDPR, which becomes legally enforceable in May 2018, requires privacy by design as well as data protection by default across all uses and applications.
As with the previous EU data protection regime, any developer serving European customers must adhere to these data protection standards even if they themselves are not located in Europe. So, if you do business in or sell to Europe, privacy by design is now your responsibility.
This presents a monumental opportunity for developers everywhere to rethink their approach to privacy. Let’s learn what PbD is and how it works.
The PbD framework was first drawn up in Canada5 in the 1990s. Its originator, Dr. Ann Cavoukian, then Privacy Commissioner of Ontario, devised the framework to address the common issue of developers applying privacy fixes after a project is completed:
The Privacy by Design framework prevents privacy-invasive events before they happen. Privacy by Design does not wait for privacy risks to materialize, nor does it offer remedies for resolving privacy infractions once they have occurred; it aims to prevent them from occurring. In short, Privacy by Design comes before-the-fact, not after.
The PbD framework has seven foundational principles:
PbD has always been available for any developer to use as a voluntary best-practice framework. Its popularity has tended to be greater in cultures that have a traditionally positive view of privacy, such as Canada and many European countries. Privacy, however, is not traditionally seen as a positive value in the US, whose companies dominate the tech world. For this reason, and for too long, web development has been approached with what at times has felt like the complete opposite of a PbD viewpoint. It has almost become normal for developers to ship apps that require social media registration, that request unnecessary permissions such as microphone access and location data, and that demand access to all of a user’s contacts.
The notion of privacy by design as a voluntary concept is about to change.
In Europe, the regulation that governs all collection and processing of personal data, regardless of use, sector or situation, has had a complete overhaul. This new set of rules, known as the General Data Protection Regulation6 (GDPR), is already on the books but becomes legally enforceable on 25 May 2018. Your business should already be working towards your wider GDPR compliance obligations ahead of this deadline, which will come up fast.
Crucially, GDPR makes PbD and privacy by default legal requirements within the EU. Not only will you have to develop to PbD, but you will have to document your PbD development processes. That documentation must be made available to a European regulatory authority in the event of a data breach or a consumer complaint.
Remember that European data protection and privacy laws are extraterritorial: They apply to the people within Europe whom data is collected about, regardless of where the service is provided from. In other words, if you develop for European customers, you must comply with EU data protection and privacy standards for those individuals, even if you yourself are not located within Europe.
Also remember that the EU, through its data protection system, has some of the strictest and most clearly defined privacy frameworks in the world; the US, by contrast, has no overarching data protection and privacy framework at all. Culture is important to remember as well. In Europe, privacy is considered a fundamental human right. Living and developing in a country where privacy is not a fundamental human right does not negate your moral or legal obligations to those who do enjoy that right.
Developers outside the EU, therefore, should consider adopting the PbD principles within the GDPR guidelines as a development framework, despite being located outside Europe. The guidelines will give you a clear, common-sense and accountable framework to use in your development process — and that framework is a lot better than having no guidelines at all.
The European data protection law defines personal data as any information about a living individual who could be identified from that data, either on its own or when combined with other information.
There is also a classification called “sensitive personal data”, which means any information concerning an individual’s
The data users generate within your app is personal data. Their account information with your company is personal data. The UID identifying their device is personal data. So is their IP address, their location data, their browser fingerprint and any identifiable telemetry.
For app developers, PbD compliance means factoring in data privacy by default
There is no checklist of ready-made questions that will get you there; General Data Protection Regulation requires developers to come up with the questions as well as the answers. But in a proactive development environment, the answers would likely take the practical forms required under GDPR, such as the following.
Good PbD practice, and its absence, is easy to spot if you know what you are looking for.
Let’s give this popular UK pub chain’s app a quick PbD audit.
The app has no settings page, which suggests no user control over privacy. This implies that downloading the app entails granting consent for data-sharing, which does not meet the second PbD principle.
8This suggestion is confirmed in the “Edit Account” option, which only allows users to edit their name and email address. This does not meet the third PbD principle “Privacy must be embedded into design.”
9The link to the privacy policy provides a blurry scan of a five-page PDF that is written for the outdated 1995 data protection directive. There are no user controls or granular options. If I wanted to exercise control over my data, I would have to write an email to a generic customer-service address or, alternatively — in the time-honored tradition of privacy policies that are really trying to fob users off — send them a letter in the post. This does not meet the seventh PbD principle of giving users granular privacy options with maximized privacy defaults.
10The privacy policy informs me that my data will be shared with third parties but gives me no indication as to who those third parties are, nor does it give me the option to withhold that data sharing. There is no distinction between third parties whose services are necessary for the transaction (for example, PayPal) and unnecessary services, such as ad networks. This does not meet the sixth PbD principle.
But let’s say I write about this stuff for a living, and so I just really need a beer. I go to the pub and fire up the Wi-Fi to use its app. When I connect to the Wi-Fi, I notice its “Settings” page. That page merely provides links to three legal documents. As with the pub’s own app, there are no settings to change, no options and no choices. There is no PbD whatsoever.
11It’s clear that the only way I can ensure my privacy with this pub chain is to not use the app or its Wi-Fi at all. This creates the zero-sum dichotomy, which the fourth PbD principle seeks to avoid.
This pub chain does not meet good PbD practice, or GDPR compliance, by any definition.
By contrast, Twitter’s recent privacy overhaul demonstrates very good PbD practice and early GDPR compliance. Here’s the catch: Its new privacy choices could have a detrimental and negative effect on users’ privacy12. The difference, however, is that it has been open and transparent and has given users educated choices and options.
13The privacy overhaul offers a range of granular privacy options, which are clearly communicated, including a clear notice that it may share your data with third parties. Users can disable some or all options.
14A prominent splash screen drew users’ attention to the changes, increasing the likelihood that they would take the time to educate themselves on their privacy options.
15A privacy impact assessment (PIA) is simply a process of documenting the issues, questions and actions required to implement a healthy PbD process in a project, service or product. PIAs are a core requirement of GDPR, and in the event of a data protection issue, your PIA will determine the shape of your engagement with a regulatory authority. You should use a PIA when starting a new project, and run a PIA evaluation of any existing ones.
The steps in a PIA are as follows:
Take some time to come up with a PIA template unique to your business or project that you can use as needed. The guidance from ICO16, the UK data-protection regulator, will help you to do that.
Good PbD practice gives users clear information and informed choices. Privacy information notices are central to that. The days of privacy policies being pages upon pages of dense legal babble, focused on the needs of the service provider and not the user, are over.
Your app, product or service should have a privacy information notice, including the following details:
Many European data protection regulators are devising standardized templates for privacy information notices, and you should check with yours to follow the progress on any required format ahead of the May 2018 deadline.
Under GDPR, the old privacy policy trick of stating “we may share your data with third parties” will no longer be considered compliant. GDPR and PbD require you to list exactly who those parties are and what they do with user data.
17As one dramatic example, PayPal’s recent updated notice lists over 600 third-party service providers18. The fact that PayPal shares data with up to 600 third parties is not news. That information is simply being brought into the open.
Good PbD compliance is not just about UX. Healthy compliance also involves implementing adequate technical and security measures to protect user data. These measures, as with other aspects of full GDPR compliance, must be documented and made accountable to a regulator on request.
PbD compliance on a technical and security level could include:
Under GDPR, companies processing certain kinds of data must appoint a Data Protection Officer (DPO), a named individual with legally accountable responsibility for an organization’s privacy compliance, including PbD. This requirement is regardless of a company’s size, which means that even the tiniest business engaged in certain kinds of data processing must appoint a DPO.
19A DPO does not have to be in-house or full-time, nor are legal qualifications required. Very small businesses can appoint a DPO on an ad-hoc or outsourced basis. Check with your EU member state’s data-protection regulator for information on your national requirements for a DPO.
We would encourage all organizations to voluntarily appoint a DPO regardless of the nature of their work. Think of a DPO as the health and safety officer for privacy. Having someone act as the “good cop” to keep your development processes legally compliant — and acting as the “bad cop” if your practices are slipping — can save you from a world of troubles down the road.
The PbD framework poses challenges that only you can answer. No one else can do it for you: it is your responsibility to commence the process. If you are within Europe, have a look at your national data-protection regulator’s GDPR and PbD resources. If you are outside Europe, we have provided some links and resources below.
Don’t view PbD as a checklist of boxes to be ticked because “the law says so,” nor think of it as something you have to do “or else.” Instead, use PbD to think really creatively. Think of all the ways that your users’ data can be misused, accessed, stolen, shared or combined. Think of where data might be located, even if you might not be aware of it. Think of what liabilities you might be creating for yourself by collecting, retaining and aggregating data that you don’t really need. Think of how the third parties you share data with, even if they are your business partners, could create liabilities for you. And in our current political climate, think about the ways that the data you collect and process could be used to do harm to your users. There are no wrong questions to ask, but there are questions that it would be wrong not to ask.
Adopting PbD into your development workflow will create new steps to follow and new obligations to meet. These steps, as onerous as they might feel, are necessary in our rapidly changing world. So, view PbD as a culture shift. Use it as an opportunity to improve your policies, practices and products by incorporating privacy into your development culture. Your users will be better protected, your business’s reputation will improve, and you will be well on the road to healthy legal compliance. In an often bewildering world, if these steps are all we can take to make a difference one app at a time, they are worth a lot.
(al)
Send * StackBlitz * A Million WebSockets and Go * Fiber * Music Blocks * Intersection Observer * GitPoint * Ha…
DeepScan is a cutting-edge static analysis tool for your JavaScript code including React, so you can develop JavaScript better, at lower cost, and more reliably.
Never heard of Hack, HHVM, XHP? Then this article by Florian Laplantif.
Send * StackBlitz * A Million WebSockets and Go * Fiber * Music Blocks * Intersection Observer * GitPoint * Ha…
Some people hate writing documentation, and others just hate writing. I happen to love writing; otherwise, you wouldn’t be reading this. It helps that I love writing because, as a design consultant offering professional guidance, writing is a big part of what I do. But I hate, hate, hate word processors.
My typical workflow using a desktop word processor goes something like this:
When writing technical web documentation (read: pattern libraries1), word processors are not just disobedient, but inappropriate. Ideally, I want a mode of writing that allows me to include the components I’m documenting inline, and this isn’t possible unless the documentation itself is made of HTML, CSS, and JavaScript. In this article, I’ll be sharing a method for easily including code demos in Markdown, with the help of shortcodes and shadow DOM encapsulation.
Say what you will about CSS, but it’s certainly a more consistent and reliable typesetting tool than any WYSIWYG editor or word processor on the market. Why? Because there’s no high-level black-box algorithm that tries to second-guess what styles you really intended to go where. Instead, it’s very explicit: You define which elements take which styles in which circumstances2, and it honors those rules.
The only trouble with CSS is that it requires you to write its counterpart, HTML. Even great lovers of HTML would likely concede that writing it manually is on the arduous side when you just want to produce prose content. This is where Markdown comes in. With its terse syntax and reduced feature set, it offers a mode of writing that is easy to learn but can still — once converted into HTML programmatically — harness CSS’ powerful and predictable typesetting features. There’s a reason why it has become the de facto format for static website generators and modern blogging platforms such as Ghost.
Where more complex, bespoke markup is required, most Markdown parsers will accept raw HTML in the input. However, the more one relies on complex markup, the less accessible one’s authoring system is to those who are less technical, or those short on time and patience. This is where shortcodes come in.
Hugo3 is a static site generator written in Go — a multi-purpose, compiled language developed at Google. Due to concurrency (and, no doubt, other low-level language features I don’t fully understand), Go makes Hugo a lightening-fast generator of static web content. This is one of the many reasons why Hugo has been chosen for the new version of Smashing Magazine.
Performance aside, it works in a similar fashion to the Ruby and Node.js4-based generators with which you may already be familiar: Markdown plus meta data (YAML or TOML) processed via templates. Sara Soueidan has written an excellent primer5 on Hugo’s core functionality.
For me, Hugo’s killer feature is its implementation of shortcodes6. Those coming from WordPress may already be familiar with the concept: a shortened syntax primarily used for including the complex embed codes of third-party services. For instance, WordPress includes a Vimeo shortcode that takes just the ID of the Vimeo video in question.
The brackets signify that their content should be processed as a shortcode and expanded into the full HTML embed markup when the content is parsed.
Making use of Go template functions, Hugo provides an extremely simple API for creating custom shortcodes. For example, I have created a simple Codepen shortcode to include among my Markdown content:
Some Markdown content before the shortcode. Aliquam sodales rhoncus dui, sed congue velit semper ut. Class aptent taciti sociosqu ad litora torquent. {{<codePen VpVNKW>}} Some Markdown content after the shortcode. Nulla vel magna sit amet dui lobortis commodo vitae vel nulla sit amet ante hendrerit tempus.
Hugo automatically looks for a template named codePen.html in the shortcodes subfolder to parse the shortcode during compilation. My implementation looks like this:
{{ if .Site.Params.codePenUser }} <iframe height='300' scrolling='no' title="code demonstration with codePen" src='//codepen.io/{{ .Site.Params.codepenUser | lower }}/embed/{{ .Get 0 }}/?height=265&theme-id=dark&default-tab=result,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'> <div> <a href="http://www.smashingmagazine.com//codepen.io/{{ .Site.Params.codePenUser | lower }}/pen/{{ .Get 0 }}">See the demo on codePen</a> </div> </iframe> {{ else }} <p><strong>Site error:</strong> The <code>codePenUser</code> param has not been set in <code>config.toml</code></p> {{ end }}
To get a better idea of how the Go template package works, you’ll want to consult Hugo’s “Go Template Primer7.” In the meantime, just note the following:
{{ .Get 0 }} part is for retrieving the first (and, in this case, only) argument supplied — the Codepen ID. Hugo also supports named arguments, which are supplied like HTML attributes.. syntax refers to the current context. So, .Get 0 means “Get the first argument supplied for the current shortcode.”In any case, I think shortcodes are the best thing since shortbread, and Hugo’s implementation for writing custom shortcodes is impressive. I should note from my research that it’s possible to use Jekyll includes8 to similar effect, but I find them less flexible and powerful.
I have a lot of time for Codepen (and the other code playgrounds that are available), but there are inherent issues with including such content in a pattern library:
For some time, I tried to embed component demos using my own iframes. I would point the iframe to a local file containing the demo as its own web page. By using iframes, I was able to encapsulate style and behavior without relying on a third party.
Unfortunately, iframes are rather unwieldy and difficult to resize dynamically. In terms of authoring complexity, it also entails maintaining separate files and having to link to them. I’d prefer to write my components in place, including just the code needed to make them work. I want to be able to write demos as I write their documentation.
demo Shortcode LinkFortunately, Hugo allows you to create shortcodes that include content between opening and closing shortcode tags. The content is available in the shortcode file using {{ .Inner }}. So, suppose I were to use a demo shortcode like this:
{{<demo>}} This is the content! {{</demo>}}
“This is the content!” would be available as {{ .Inner }} in the demo.html template that parses it. This is a good starting point for supporting inline code demos, but I need to address encapsulation.
When it comes to encapsulating styles, there are three things to worry about:
One solution is to carefully manage CSS selectors so that there’s no overlap between components and between components and the page. This would mean using esoteric selectors per component, and it is not something I would be interested in having to consider when I could be writing terse, readable code. One of the advantages of iframes is that styles are encapsulated by default, so I could write button { background: blue } and be confident it would only apply inside the iframe.
A less intensive way to prevent components from inheriting styles from the page is to use the all property with the initial value on an elected parent element. I can set this element in the demo.html file:
<div> {{ .Inner }} </div>
Then, I need to apply all: initial to instances of this element, which propagates to children of each instance.
.demo { all: initial }
The behavior of initial is quite… idiosyncratic. In practice, all of the affected elements go back to adopting just their user agent styles (like display: block for <h2> elements). However, the element to which it is applied — class="demo" — needs to have certain user agent styles explicitly reinstated. In our case, this is just display: block, since class="demo" is a <div>.
.demo { all: initial; display: block; }
Note:all is so far not supported in Microsoft Edge but is under consideration. Support is, otherwise, reassuringly broad9. For our purposes, the revert value would be more robust and reliable but it is not yet supported anywhere.
Using all: initial does not make our inline components completely immune to outside influence (specificity still applies), but we can be confident that styles are unset because we are dealing with the reserved demo class name. Mostly just inherited styles from low-specificity selectors such as html and body will be eliminated.
Nonetheless, this only deals with styles coming from the parent into components. To prevent styles written for components from affecting other parts of the page, we’ll need to use shadow DOM10 to create an encapsulated subtree.
Imagine I want to document a styled <button> element. I’d like to be able to simply write something like the following, without fear that the button element selector will apply to <button> elements in the pattern library itself or in other components in the same library page.
{{<demo>}} <button>My button</button> <style> button { background: blue; padding: 0.5rem 1rem; text-transform: uppercase; } </style> {{</demo>}}
The trick is to take the {{ .Inner }} part of the shortcode template and include it as the innerHTML of a new ShadowRoot. I might implement this like so:
{{ $uniq := .Inner | htmlEscape | base64Encode | truncate 15 "" }} <div></div> <script> (function() { var root = document.getElementById('demo-{{ $uniq }}'); root.attachShadow({mode: 'open'}); root.innerHTML = '{{ .Inner }}'; })(); </script>
$uniq is set as a variable to identify the component container. It pipes in some Go template functions to create a unique string… hopefully(!) — this isn’t a bulletproof method; it’s just for illustration.root.attachShadow makes the component container a shadow DOM host.innerHTML of the ShadowRoot using {{ .Inner }}, which includes the now-encapsulated CSS.I’d also like to include JavaScript behavior in my components. At first, I thought this would be easy; unfortunately, JavaScript inserted via innerHTML is not parsed or executed. This can be solved by importing from the content of a <template> element. I amended my implementation accordingly.
{{ $uniq := .Inner | htmlEscape | base64Encode | truncate 15 "" }} <div></div> <template> {{ .Inner }} </template> <script> (function() { var root = document.getElementById('demo-{{ $uniq }}'); root.attachShadow({mode: 'open'}); var template = document.getElementById('template-{{ $uniq }}'); root.shadowRoot.appendChild(document.importNode(template.content, true)); })(); </script>
Now, I’m able to include an inline demo of, say, a working toggle button:
{{<demo>}} <button>My button</button> <style> button { background: blue; padding: 0.5rem 1rem; text-transform: uppercase; } [aria-pressed="true"] { box-shadow: inset 0 0 5px #000; } </style> <script> var toggle = document.querySelector('[aria-pressed]'); toggle.addEventListener('click', (e) => { let pressed = e.target.getAttribute('aria-pressed') === 'true'; e.target.setAttribute('aria-pressed', !pressed); }); </script> {{</demo>}}
Note: I have written in depth about toggle buttons and accessibility11 for Inclusive Components.
JavaScript is, to my surprise, not encapsulated automatically12 like CSS is in shadow DOM. That is, if there was another [aria-pressed] button in the parent page before this component’s example, then document.querySelector would target that instead.
What I need is an equivalent to document for just the demo’s subtree. This is definable, albeit quite verbosely:
document.getElementById('demo-{{ $uniq }}').shadowRoot;
I didn’t want to have to write this expression whenever I had to target elements inside demo containers. So, I came up with a hack whereby I assigned the expression to a local demo variable and prefixed scripts supplied via the shortcode with this assignment:
if (script) { script.textContent = `(function() { var demo = document.getElementById('demo-{{ $uniq }}').shadowRoot; ${script.textContent} })()` } root.shadowRoot.appendChild(document.importNode(template.content, true));
With this in place, demo becomes the equivalent of document for any component subtrees, and I can use demo.querySelector to easily target my toggle button.
var toggle = demo.querySelector('[aria-pressed]');
Note that I have enclosed the demo’s script contents in an immediately invoked function expression (IIFE), so that the demo variable — and all proceeding variables used for the component — are not in the global scope. This way, demo can be used in any shortcode’s script but will only refer to the shortcode in hand.
Where ECMAScript6 is available, it’s possible to achieve localization using “block scoping,” with just braces enclosing let or const statements. However, all other definitions within the block would have to use let or const (eschewing var) as well.
{ let demo = document.getElementById('demo-{{ $uniq }}').shadowRoot; // Author script injected here }
Of course, all of the above is only possible where shadow DOM version 1 is supported. Chrome, Safari, Opera and Android all look pretty good, but Firefox and Microsoft browsers are problematic. It is possible to feature-detect support and provide an error message where attachShadow is not available:
if (document.head.attachShadow) { // Do shadow DOM stuff here } else { root.innerHTML = 'Shadow DOM is needed to display encapsulated demos. The browser does not have an issue with the demo code itself'; }
Or you can include Shady DOM and the Shady CSS extension, which means a somewhat large dependency (60 KB+) and a different API. Rob Dodson was kind enough to provide me with a basic demo13, which I’m happy to share to help you get started.
With the basic inline demo functionality in place, quickly writing working demos inline with their documentation is mercifully straightforward. This affords us the luxury of being able to ask questions like, “What if I want to provide a caption to label the demo?” This is perfectly possible already since — as previously noted — Markdown supports raw HTML.
<figure role="group" aria-labelledby="caption-button"> {{<demo>}} <button>My button</button> <style> button { background: blue; padding: 0.5rem 1rem; text-transform: uppercase; } </style> {{</demo>}} <figcaption>A standard button</figcaption> </figure>
However, the only new part of this amended structure is the wording of the caption itself. Better to provide a simple interface for supplying it to the output, saving my future self — and anyone else using the shortcode — time and effort and reducing the risk of coding typos. This is possible by supplying a named parameter to the shortcode — in this case, simply named caption:
{{<demo caption="A standard button"}} ... demo contents here... {{</demo>}}
Named parameters are accessible in the template like {{ .Get "caption" }}, which is simple enough. I want the caption and, therefore, the surrounding <figure> and <figcaption> to be optional. Using if clauses, I can supply the relevant content only where the shortcode provides a caption argument:
{{ if .Get "caption" }} <figcaption>{{ .Get "caption" }}</figcaption> {{ end }}
Here’s how the full demo.html template now looks (admittedly, it’s a bit of a mess, but it does the trick):
{{ $uniq := .Inner | htmlEscape | base64Encode | truncate 15 "" }} {{ if .Get "caption" }} <figure role="group" aria-labelledby="caption-{{ $uniq }}"> {{ end }} <div></div> {{ if .Get "caption" }} <figcaption>{{ .Get "caption" }}</figcaption> {{ end }} {{ if .Get "caption" }} </figure> {{ end }} <template> {{ .Inner }} </template> <script> (function() { var root = document.getElementById('demo-{{ $uniq }}'); root.attachShadow({mode: 'open'}); var template = document.getElementById('template-{{ $uniq }}'); var script = template.content.querySelector('script'); if (script) { script.textContent = `(function() { var demo = document.getElementById('demo-{{ $uniq }}').shadowRoot; ${script.textContent} })()` } root.shadowRoot.appendChild(document.importNode(template.content, true)); })(); </script>
One last note: Should I want to support markdown syntax in the caption value, I can pipe it through Hugo’s markdownify function. This way, the author is able to supply markdown (and HTML) but is not forced to do either.
{{ .Get "caption" | markdownify }}
For its performance and its many excellent features, Hugo is currently a comfortable fit for me when it comes to static site generation. But the inclusion of shortcodes is what I find most compelling. In this case, I was able to create a simple interface for a documentation issue that I’ve been trying to solve for some time.
As in web components, a lot of markup complexity (sometimes exacerbated by adjusting for accessibility) can be hidden behind shortcodes. In this case, I’m referring to my inclusion of role="group" and the aria-labelledby relationship, which provides a better supported “group label” to the <figure> — not things that anyone relishes coding more than once, especially where unique attribute values need to be considered in each instance.
I believe shortcodes are to Markdown and content what web components are to HTML and functionality: a way to make authorship easier, more reliable and more consistent. I look forward to further evolution in this curious little field of the web.
(vf, al, il)
For many people, a map of a transportation network is a given, an expected part of the system, something that just is — like a fire-escape plan in a building. So, when I say that I design transportation maps, they don’t understand. What is there to design even?
Well, let’s take the London underground map as an example. Designed by Harry Beck, it was the world’s first transportation map to use the principles of electrical circuit drawings. All line segments were put to the angles of 45 or 90 degrees. The distances between stations were equalized. I wrote about it in part three of my “Maps and Reality” series, “Diagrams1.”
This schematic approach was later adopted for many transportation maps of the world. But not every time was this a good idea. This is one useless map (from Samara, Russia):
3It adds almost nothing beyond just listing the stations: Алабинская · Российская · Московская · Гагаринская · Спортивная · Советская…
Beck’s design dealt with growing complexity and the spread of London’s underground rail network. When there is just one line, it’s better to put this line in context. See the Ekaterinburg metro map5, for example:
6Every transportation network requires a specialized solution.
Let’s look at New York. The subway is large and complicated but quite different from London’s: Trains can have different routes, which are denoted by both numbers and letters. In 1972, Massimo Vignelli designed this map:
13In London, ticks are used to depict stations:
15Vignelli couldn’t have used them in New York. In London, lines rarely run together through the same stations. And when they do, all trains in a “wisp” stop at all of them — see Great Portland Street and Euston Square above.
In New York, such wisps are everywhere, and some trains don’t stop at some stations. So, when there is a stop on a particular route, Vignelli puts a black bullet on the route’s line:
17You can see that, at some stations, not every line has a bullet.
Vignelli’s map was beautiful but, unfortunately, unsuccessful. People considered it too abstract. Having no geographical reference, the eye had nothing to catch on. Also, the stations named with street numbers looked identical — the font was just too small for that.
This design was the closest to London’s that New York has ever seen.
The successful design was the one by Michel Hertz (1979) — still in use. It includes parks, ponds, main streets and area names:
19The related routes are denoted with just one line, not a wisp:
21But there’s a list of stopping routes at each station. Look at the red line, for example. Only route 1 stops at 18th, 23rd and 28th Streets, but all routes stop at 14th and 34th Streets.
Hertz wanted his map to look geographical. But he knew that a “true” map would use the format very inefficiently. So, his map is actually distorted significantly for everything to fit. Compare Google Maps on the left to Hertz’s map on the right:
23Hertz’s map doesn’t look stylish. But it has proven to work well. This is a very specific, bulletproof design tailored to New York.
But even maps that appear to be much more alike in principle have many little details to serve their cities’ needs.
On stations, there are tracks for opposing directions. In some cities, these tracks are marked with the names of the lines’ terminals.
25The terminals are, thus, important for wayfinding, so they have to be emphasized on a map. In Barcelona, they put the terminal’s name on a background, whose color matches the line’s:
27In Paris, they use bold font and symbols for the line numbers:
29This is unnecessary in London, where, instead of toponymics, they use geographic directions (for example, “Northbound”).
In Oslo, a thick wisp of lines passes through the city center. One of the lines forms a loop and passes several stations twice: first as line 4, then as line 6. The transformation from 4 to 6 is shown with a gradient — not a typical element indeed:
31There is another detail in Oslo: Trains pass Gulleråsen station in only one direction. This requires a designation, an element that is not used in any of the maps we’ve discussed above:
33Moscow has its own peculiarity: For historical reasons, the stations have different names on different lines (sick, but what can you do). In addition, the Moscow metro map has to use both Cyrillic and Latin scripts for its station names. Depiction of transfers turns into a problem. Here, eight names must be positioned around the “Biblioteka Imeni Lenina — Aleksandrovsky Sad — Arbatskaya — Borovitskaya” junction, where four lines intersect:
34A whopping six lines intersect at London’s “King’s Cross St. Pancras” station; just one name suffices:
36There is not a single place on London’s giant map where a station name intersects a line — there is always space around the lines. To achieve this in Moscow, one would need to dramatically reduce the font size and complicate the line geometry. That’s why Moscow’s metro map includes a device that the London one does not: a semi-transparent background for the station names that cross lines (see above).
But London has its own complication, one absent in Moscow. The gray “clouds” delineate the payment zones — something Moscow does not need because the price of a ride is fixed:
38Every city and transportation network has a lot of details, which makes it impossible to use exactly the same graphical principles everywhere. But there is another reason for maps to be so different: aesthetics.
A transportation map is not only a tool, but also a notable object of graphic design in a big city. So, if you opt for Beck’s design language, you would get a London-like map, no matter what you depict. The transportation system must have a face, and aesthetics are as important as logic.
The main feature of the Moscow metro map is the circle line. It doesn’t fit Beck’s language, but it’s very important to Moscow. This is not of Moscow:
40This, on the other hand, is:
41London also has a line named Circle, but it has never been depicted as a circle. Today, it’s not even a closed loop:
43These circle lines are major elements and form the overall impression of the map.
But little details also influence the perception of a map.
In London, the black rings of the transfer stations are noticeably thinner than the lines. The “corridors” are of the same width. The stations’ ticks are square, sticking out at two thirds of a line’s width. The names are typeset with blue New Johnston:
45In Moscow, the fat rings of the transfers are colored with their lines’ colors. The corridors are much thinner and have a gradient. Some transfers are circular. The station ticks stick out at a full line’s width. The names are typeset with black Moscow Sans:
47Look at this tram map:
49It’s obvious that it’s a tram map for London, not for some other city. It follows London’s transportation graphic design standards — the rings, the ticks, the captions.
When we see the beige background, the particular palette of the lines, the filled station disks and the distinct designation of the transfers, we immediately recognize the Paris map:
51Jug Cerović follows an unusual 18-degree-angle grid in his Luxembourg map. Once you see it, you’ll recognize it every time:
53For Chelyabinsk’s trams map55, we’ve come up with these 3D terminals:
56Why are they like this? The only reason is that we wanted this map to look special.
It is not enough for a good transportation map to just answer the question, “How do I get there?” Because it is used everywhere, it is a part of the city’s image. And if its design is powerful, it will influence the city in other ways.
Moscow’s circle line has inspired designers to create this beautiful wayfinding signage:
58The round designations of New York’s subway train routes are used in all of the signage and have even made it to the dots of the i‘s in the pedestrian city maps (in the classic Helvetica these dots are rectangles):
60And in London, the tube map has given birth to the graphical language of all transportation-related signage:
62This graphical language is so iconic that you can even buy all sorts of souvenirs with its elements: t-shirts, umbrellas, shower curtains. This design has spread not only beyond the Tube, but beyond London. All sorts of maps are now done in this style:
64Strong graphic design makes transportation systems more attractive. This helps cities get rid of privately owned cars. People spend more time outside, interacting with each other. This gives small businesses a boost and makes cities more pleasant to live in.
(vf, al, il)
Fractures helps you bootstrap design systems and prototypes by providing a set of non-blocking, atomic, utility classes.
CSS is an amazing tool which we constantly use but we don’t seem to honor it appropriately. Whenever I see the growing browser support of the :focus-within selector, the much wanted justify-content: space-evenly for Flexbox or how great CSS Grids already work, I feel really grateful to have such awesome tools available to work with.
And with advanced new media queries such as prefers-reduced-motion, screen and (color), or pointer, we get amazing tools to improve accessibility and usability of our websites. Just let the user be in control how to view your amazing design and it’ll be a success for everyone.
:focus-within CSS pseudo-selector11 is a nice way to enhance your form sections further. Browser support12 is still a bit limited so far but it’s already worth thinking about adding it to your code to improve design and usability for those whose browser support the selector already.justify-content: space-evenly13. This new setting places even space between and to the outer of the elements — a feature we all wanted to have very much in Flexbox. It already works in Firefox, and Safari Tech Preview and Chrome Canary have the support as well.
16
20—Anselm
Whether you’re into good ol’ drawing and painting, or quick editing in Photoshop or Illustrator, one thing’s for sure: they’re all creativity’s best friends. Some draw pictures all day1, while others find their inspiration in uncommon sources2 in order to break out of the box. Whatever it is that you decide to do, it’s good to challenge yourself more often and get out of your comfort zone. If you don’t, you may never discover something that you love doing, or perhaps even worse, never learn a whole lot about yourself.
If your excuse are pesky blackouts or simply having no clue what to create nor where to get started, don’t fret! Even the most talented artists out there practice so much more than you’d ever imagine, and hone their skills by trying out copywork3. The most important thing is to be confident and simply give it a try. For more encouragement, I’ve collected a good number of inspirational artwork that is bound to give you that spark you need to get started already!
It’s quite obvious where they got the inspiration from. Very well executed.
Hard not to love this. Just look at the shadow and light effect on the Atomium, and the subtle texture pattern in the spheres. So well done.
10Interesting choice of colors. It gets the adventure spirit going. Those line textures are also very well applied.
12Beautiful timing to get that amazing golden hour work for you. Combine that with Paris and you get this result.
14Love the hairline, handlebar and wheels. Super cool!
16An editorial illustration for DB Magazine in the US on the subject of the dangers of hackers within the hospital system. Beautiful style, colors and patterns.
18Nice perspective, and beautiful style. I love the radio.
20The surreal world of Sébastien Plassard.
22Such a beautiful shot with a perfect fly-by by those birds. Amazing colors.
25A selection of recent prints created with a wildlife theme. Go see the others27, too.
28Beautiful! However, when your legs don’t want to cooperate it can be something else.
30One of winners of Communication Arts 2017. I love the duplicity in here. Very clever!
32Wonderful usage of vivid colors used in this fragrance brand illustration.
34The muted colors work very well together. I’m also inspired by the simplicity of the shadows.
36The reflection in the helmet, and reflection of the light on the suit are nicely executed.
38Much to love in here such as the custom typography, the special dog and the color palette.
40Simply gorgeous!
42Still from an illustrated animation. The finished video44 of Festival Bienal is quite nice.
45Love the elegance in this design style.
47The suspense is all over this illustration for the novel The Thirty-Nine Steps. Makes me want to read it.
50Inspired by those long countryside curved roads. Love how the colors are applied.
52Love the amount of detail and simplicity with the 1 line weight and the minimal use of color.
54Wonderful landscape and atmosphere with fog, foreground and one red poppy!
56So many things to discover in this beautiful piece. Made me smile. I really love the busyness here. So well executed.
58Great poster. Love the impressive impact. Read about the design process61.
62Great geometry and wonderful reflection of the sky.
64Inspired by those long countryside curves. You feel the speed in this one. Available as a poster.
66Part of a selection of characters which personified the incredibly functional yet stylish Rain collection. See the other characters68, too.
69Lovely mix of colors and beautiful custom typography.
71Playing with color, shapes and shadow. That’s what you’ll see in this series called Colorful Boxes. Absolutely love the very bright colors in this one.
73Amazing capture! It’s Antelope Canyon in Arizona. It looks so surreal, just like paint strokes.
75The 45 degrees lines made the final work looks really unique. Look at the shadow and light effect on the cactus. So well done.
77Views like this are the reward for all the suffering to get there.
79Opening illustration for an article about the history of the book. Beautiful style and details! The hair is nicely done.
81Inspiring color combinations.
83Great shadows and gradients, and lovely soft style.
85Great unity. Love the cute detail of the dog running away.
87Perfect example on what you can achieve when using negative space.
90Gotta love the cacti as well as the colors here — obviously.
92An illustration for Etsy for their medium blog about designing for growth.
94Dealing well with flood of information. Very well translated.
96Nicely done Mind The Gap train safety poster.
98Beautiful color palette in this one. The reflections on the windows are nicely done.
100Never stop exploring! Fantastic action shot with superb light.
102Pretty sweet texture work and great color choices.
104Admiring the simplicity of this style.
106Not your everyday color palette. I really like the idea of leaving color out. Beautiful design style.
108Always a pleasure to introduce some new work from Mads. Love how he played with perspective in this one.
110Look at those majestic mountains! What an awesome road to ride your bike on.
112That clarinet player is just perfect. I love how his finger draws your eye up to the piano player with that matched fine line.
114Dapulse is the next generation of visual tools, built for designers and developers.
What could be so difficult about designing a decent date picker? Basically, we just need an input field and an icon that represents a calendar clearly enough, and once the user clicks on that icon, we pop up a little overlay with the days lined up in rows. Right?
Well, not every date picker fits every interface, just like not every interface actually needs a date picker. But when a date picker is required, quite often it’s just a bit too tedious and annoying to specify that one date, and too often it produces irrelevant results or even a zero-results page, although just a few minor refinements would make it much easier to use.
Over the last few years, I’ve spent a lot of time working with various companies trying out various approaches and studying them in usability tests. This series of articles is a summary of observations and experiments made throughout that time. Over the course of months, we’ll be exploring everything from carousels to car configurators. Having looked into the design of accordions1 two weeks ago, let’s look into the design of date and time pickers today — in all the various facets and flavors of their visual appearance and interaction design.
First things first, though: Date pickers are often considered to be a foolproof component for date selection — predictable, consistent, generic — and so more often than not, we use them just because they seem to be a universally accepted pattern for date input. But just like any other form element, sometimes they should be the method of last resort, aiding the user’s input if it can’t be inferred in a better way. Now, there are situations where date pickers are extremely helpful, and there are situations where they just slow users down. Our job, then, is to carefully study our own scenarios and figure out an optimal way to frame the question of time and date to help users provide the input quickly and easily.
The best input is the one that matches the user’s intent, without having to ask the user to be precise, of course. But what if we set a budget on the date input as at most two taps? Three taps for a date range? Five taps if we bring a time slot into the game as well? You might be wondering if it’s really a big deal; after all, it’s just a tiny little date picker! If date selection is front and center in your interface, you should expect users to use it a lot, and going to extremes to optimize date input isn’t really a matter of optimization, but is rather a core element of your website’s experience.
In fact, there are plenty of contexts in which date pickers matter: whether it’s for a medical appointment, a spa treatment, a boat rental, a TV guide, online banking, a flight ticket or a summer cottage rental — pretty much anything that requires date input is likely to have some sort of a date and time picker. And more often than not, all such websites tend to use the same (jQuery) implementation, plugged into the UI a while back and happily forgotten ever since. However, it might not be the best option for your particular case.
If we look closely at the nature of a date picker, there are a good number of design questions to be resolved — and many of them aren’t straightforward at all:
Indeed, we have many decisions to consider, and most of them aren’t that straightforward at all. But let’s tackle one issue at a time. The main question we should ask ourselves first is what problem and in which context exactly are we solving and how can a date picker help there or, more specifically, what kind of a date picker would help users move forward in completing their task seamlessly.
Before choosing an interface pattern to apply to your problem, it’s important to understand what kind of date input you actually need. Is it enough to know just one day, or do you need a date range? The latter doesn’t mean that you have to use two date-pickers, though, but it will affect the interaction and the design of the component.
You might also want to extend the date picker with a time input, but it doesn’t mean that the experience has to happen in steps — date picker first, time picker second. There are also ways to integrate both the day and time selection in one single component. We’ll explore some of them later in the article.
Beyond that, it’s a good idea to look into the expected range of values that your visitors will most likely type in. Perhaps you’ll need to extend the date input with a set of predefined options, or limit the range of accepted values, or complement it with numerical input so that customers can type in the values manually. In fact, the latter option might be useful more often than not — the problem is that it’s quite difficult to get right.
One thing is certain: If you’ve been considering a date picker, chances are high that, you know, you need some sort of a date input (duh!). You could, of course, use three separate numerical inputs, separated by a separator symbol — perhaps a <select> dropdown for the day, month and year — but with that design, users will embark on a journey through tapping and scrolling, which isn’t necessarily the most seamless or fastest experience. We want the date to be chosen as quickly as possible, and being able to set the date with two taps (tap to open the calendar, and tap to pick a day) would be much easier than dealing with three separate input fields.
5select dropdown for date selection. It prompts a long scrolling area and might not be the fastest way to input. (View large version7)All right, then. What if instead of three separate inputs, we keep only one — perhaps with the format helper DD/MM/YYYY, for example? As the user starts typing, the transition between day and month and year should happen seamless and automatically, so that the user wouldn’t need to do anything but keep typing on the numerical keyboard. Ideally, they’d be finished with the input after, at most, eight keystrokes. Obviously, we can’t assume whether the user knows the exact date, but it would be useful to make precise input possible, complementary to a regular date picker. Especially in interfaces where the date input can vary a lot (such as with passport expiry dates), typing the value instead of endlessly tapping through years and months just sounds more reasonable, right?
Well, numerical input has to be reliable enough to manage all kinds of edge cases — and there are plenty of them. Of course, we’ll be using some sort of a label or placeholder to indicate the order of the day, month and year input and an example of the input format, but inline validation should pick up an ill-formatted input quickly and suggest corrections to drive the user forward in the input flow. Watch out for the day on which the week starts. If your company is international and most customers come from the US, then you’ll probably need to change the UI based on the user’s location or preferences to avoid misbookings.
Being reliable also means being forgiving. If the user wants to select March 1st, 2019, with the numerical input MM/DD/YYYY, they would need to type in 01 / 03 / 19. As designers, that’s exactly the input we are expecting.
Now, how would users type in the data when encountering that numerical input? If you observe users typing in a date in an input, you’ll see them pause for a second, type in 1, then manually switch to the month input, type 3, then manually switch to the year input and type the year — either 19 or 2019.
Other users will play it safe and type in 03 and 01 explicitly. Still others will try to include a separator sign in either of these inputs. Because in some implementations the placeholder disappears once the input is activated, some users will use a different separator sign than the one you’ve accounted for — often a hyphen (-) or slash (/). Some users will try to increment the value by using the up and down arrows in the input fields. And some users will choose to tab through the fields when typing in the date. Oh, what a nightmare it is for inline validation!
10Why do users do this? Mostly because they have been burned in the past — by clunky interfaces whose data input was designed poorly, resulting in a frustrating experience of going back and forth — for example, seeing an incorrectly interpreted input, then hitting a tiny day or month selection input to correct it, but ending up resetting the other input as a result. In all of these cases, it’s easy to get frustrated. And in all of these scenarios, the designer’s implementation should be able to properly interpret the input and support the user, rather than throwing errors left and right (with autocomplete or smart suggestions).
Keep the date format suggestion (in the placeholder) when the user activates the input field. Keep the delimiters and placeholders displayed as the users manually inputs the date. If that’s not possible for some reason, use a floating label to continue displaying the format (this does have some accessibility issues12, but there are some13solutions14 as well.)
Numerical input matters in cases where the range of input varies widely — potentially spanning years, such as visa validity dates, or accounting for predictable input, such as birthday dates. That’s where it’s worth investing into a proper numerical input. You could even take it to the next level, supporting actual context-sensitive input. Perhaps instead of asking for a specific input format, you could support queries such as “yesterday,” “now,” “today,” “next Friday,” “one year ago,” “two weeks ago” or even “5 days into July.”
15
16Depending on the nature of your application, allowing for flexible dates might be useful, and typing the query in the input field would be easy enough. If that’s not possible, then it might be a good idea to add easily tappable, predefined options for “today,” “tomorrow,” “in 7 days” and so on alongside the date picker. It could be useful when searching for the optimal fare for an airline ticket. In fact, that’s exactly the technique that Kremlin.ru1817 uses. Of course, you also need to communicate that you support this kind of “smart” fuzzy input prominently as well.
While numerical input is useful and it’s good to have it available as a fallback, in some situations a date picker is infinitely more useful — for example, when the customer is booking a short vacation. What if the user is looking for a quick weekend trip within the next six weeks, but they don’t have exact dates in mind — instead, they are exploring pricing and availability, which means they will be jumping between days and weeks, and potentially even months, a lot. In such cases, numerical input would be way too slow and tiring, whereas a calendar view would be way more relevant because it displays weekend options lined up in a grid upon a tap.
If we examine the interaction with the date-picker input field a bit closer, we’ll stumble upon a number of micro-decisions around its interaction design. Should the input field have default values, or should it be left blank, perhaps populated with a date placeholder, showing an example of the correct input? If we do use default values, which values do we choose? And once the user has selected dates but refreshes the page, should the input be persistent in the fields or reset automatically?
19Frankly, we didn’t test, nor did we spot any preference for, any of the options above, but it seems that setting random values for the customer isn’t really the best option because it would force customers to “fix” the values from the seemingly random ones to the ones they are actually looking for. However, if your customers are likely to buy last-minute deals on your website (be it shows, public transportation or hotels), then the current date (“today”) or even current time (“now”) might be a good option — especially in a time-sensitive context, like a TV guide. The final decision will come from the general behavior you’ve gathered from your frequent customers.
22Once the user has selected dates or time slots but refreshed the page (accidentally or deliberately), we can choose to cancel the selection or keep it as is. If the user accidentally refreshed, they won’t be delighted about their input being lost and having to retype it again. That’s frustrating. If the user deliberately refreshed, they’d see predefined dates and have to “fix” the dates. This can be quite frustrating as well, unless you provide a noticeable “Reset” or “New search” link next to the date input. Instead of manually deleting all of the previous input, the customer can clear the selection with one tap. This is also where a mini-stepper could be helpful as well, as dates might not change significantly. In that latter case, adjusting the date using two native scroll wheels, for example, would be just way too annoying.
In a nutshell, it’s a good idea to prepopulate the dates only if you are certain that the user is likely to choose these dates; also, persist data after a page refresh (unless the input is time-sensitive), and add a “Reset” link to enable the user to cancel their input easily. By the way, that reset link should probably be available in the calendar overlay as well.
One might think that you’d need to be really creative to come up with a distinct design for the calendar overlay. After all, they are so generic most of the time! Usually, the overlay appears under the date-input field, and mostly as a full-screen overlay on narrow screens and as a smaller panel on the desktop. The days are lined up in rows, grouped as weeks, with drop-downs to navigate the years and months. However, as it turns out, a calendar overlay could contain various level of detail and navigation.
The simplest question is, should the week row start on Monday or Sunday? Well, it depends on the service you are providing and the audience you are targeting. Should a date picker always contain the year input? Probably not on a public transportation website, a TV guide or a food delivery service. Should you display all day options and month options all the time? Probably not if you are designing a car rental website — you probably wouldn’t need to book a car more than a few months in advance. And if you are using these services in months when the next year could be an option — such as in mid-December — you might get away without displaying the year, because January would obviously be January of the upcoming year.
25
28There is another level of complexity to it, though. In some situations, displaying an actual day of the week (Monday, Tuesday, etc.) is important (for example, for booking an appointment). In other situations, it’s irrelevant (such as for a birthday). Sometimes we do want to display availability or pricing (such as for booking a flight). And sometimes we want to know a date range (for renting a summer cottage) or an exact time slot (a restaurant reservation), rather than just a date. In such cases, we need to complement a date selection with a time-slot selection, or indicate the connection between the start date and end date somehow.
It’s worth considering the level of detail to provide in your date picker early on to help users make an informed choice more quickly. If availability matters, consider clearly separating available and unavailable options. Additionally, if there are different options or price tags associated with different dates, then it might be useful to color-code to indicate better fares or better availability. If many customers are booking your services over the weekend, clearly indicate weekends and, potentially, public holidays.
What would you choose to highlight for a selected day in your interface? Perhaps availability on that day? Maybe different opening or closing times? The kind of show running on that particular day? It’s also a safe bet to restrict or disable certain selections, or at least provide a hint right away in the calendar if a selected date range won’t bear the expected result.
31Figure out the critical detail that’s important to your customers and expose it prominently — for example, with gray dots (to denote unavailable) and green dots (available). The latter could appear in different sizes, for different grades of availability. It doesn’t have to be a full-detail view, though — potentially, even a color gradient overlay would do the job, with a list detail view that could be progressively disclosed once the date is selected.
It’s easy to get lost among all those fine features and indicators, but it’s also critical to get the basics right first. Don’t forget to indicate the current day, so that customers can easily see the relationship between a remote date and the current date.
Obviously, you will need the day and probably the month most of the time, but you might not need to display the year all the time. Or at least, if the year isn’t used that much, it doesn’t have to be as prominent as the other input, and perhaps appear only when needed, with some sort of progressive disclosure. In all of these cases, you’ll also need to include some sort of navigation between days, months and years. It doesn’t have to be only a select drop-down though.
For date selection that is not so fixed, such as a wedding date or the beginning of employment, you might want to look into a more dynamic input that would complement a good ol’ date picker — for instance, a mini-stepper.
If many customers are likely to explore a quite short range of date options, you could add quick “previous” and “next” navigation next to the day input right in the input field. For example, when booking a weekend trip, a user might want to leave either on late Thursday or early Friday, but late Saturday is definitely out of question, so instead of retyping the input or selecting the date in the calendar overlay, a single tap would produce the expected result.
In fact, that’s exactly what Google Flights38 uses as an addition to its date-range picker. To be able to jump quickly between months and years, you could add a mini-stepper for them as well (again, think how quick the change of the date would be for a passport expiry input).
41In general, a mini-stepper is a good enhancement for every date picker. However, it probably shouldn’t be considered a replacement for a calendar overlay. Of course, tapping is easy; but it can also get very tedious very quickly. In usability sessions, you can see how the annoyance level (and blood pressure) increase with every tap after the 10th tap. Eventually, some users switch to numerical input instead altogether (if it’s possible, of course).
44So, what to choose? Study the purpose of the calendar and the scope of the date input range first. If the date is likely to be quite far in the past or the future (for example, for booking a vacation), then a numerical input with a date picker might be a good option. If the date input range is usually quite short (less than six weeks, such as when booking a medical appointment), definitely consider adding a mini-stepper for quicker jumps.
Ideally, providing all three options — a numerical input, a calendar overlay and a mini-stepper — seems to be a safe bet, as long as numerical input is reliable enough. If there are only a few options to display at a time, then perhaps a date picker isn’t necessary for your interface at all. Consider displaying predefined options as links, buttons or perhaps even a slider, instead of prompting a calendar overlay.
47Date input doesn’t necessarily require a date picker, but usually a date picker is a good solution. However, not all date pickers are created equal, and interaction design will vary quite significantly depending on the context. One thing is certain, though: Unless the date picker is displayed as is in plain sight, it will have to be prompted by a click or tap on an input field or a date picker icon (usually some sort of a calendar icon).
50Here’s another question: Should the overlay appear when the user chooses to click on the calendar icon or on the input field — or both? Of course, if numerical input is possible, the click on the input field shouldn’t trigger the calendar. However, if that’s not the case, the entire field should trigger the date picker overlay. But maybe we should treat the use case of a user manually prompting a date picker as an exception rather than a rule for interaction with our interfaces?
It’s quite remarkable that in many interfaces, date selection is usually not the very first data that the user is asked for. For some mysterious reason, it is often preceded by other, often more general, input.
For example, booking interfaces usually ask users about the destination of their journey before asking for the dates. While the calendar overlay should, of course, be triggered by a tap on the icon and in many cases the input field, what if it was triggered automatically once the user finished the preceding input?
Ryanair57, for example, seamlessly drives the user forward through the input, displaying the date picker automatically. When the initial date selection is done, the second date picker for the end date is triggered automatically. In an ideal scenario, then, defining a date range takes just two taps, unless you have to switch between months. The interface takes care of this issue: At any point of time, the date picker displays the view with two months at a time (on both narrow and wide screens). Because most journeys are unlikely to span more than two months, jumping between months is often not necessary, and input can be achieved much faster. Unfortunately, the website is hardly accessible, which makes input literally impossible with voiceover.
The selected range is visualized immediately by connecting the dates visually in the calendar with a background color change. This range should be announced by a screen reader as well when a selection is made.
This simple technique boosts completion of the date-range input because no click or tap on the date-input field or icon is required in the entire interaction. By always moving forward in the form, the user never has to actively switch or think about the date selection — everything is literally just a tap away.
It’s all good if a date picker is used every now and again, but what if you wanted to really power-boost the experience for your frequent customers? What are the common issues that keep appearing? How can interaction with a date picker be designed even better?
That’s where we need to dive slightly deeper into the features and functionality that a date picker might provide. What if you included keyboard shortcuts to enable keyboard-accessible selection of the date and movement by days, weeks or months? It might be helpful to be able to jump to the first or last day of a week, and to escape to the date input field.
62
63
64That’s exactly what Airbnb does. In fact, Airbnb’s date picker is open-sourced66 and can be used right away as a React component — comprehensive and bulletproof, and it supports localization as well. If your customers are relying on a date picker, enabling them to jump between dates via keyboard shortcuts does have a learning curve, but it could be a real boost. It would be quite difficult to make a date picker more powerful than that.
When we think about date selection, we probably imagine a couple of input fields along with a calendar overlay. Date selection doesn’t have to use form elements at all, though. Here’s an idea: What if we used a conversational interface with smart defaults, asking the customer to either type or choose the day, month and year — obviously, with a date picker, just in case the date doesn’t come up in the overview of predefined options. Adhithya Kumar built a quick Invision mockup67 of what the basic interaction could be like. You’ll find a couple of examples of such interaction below as well.
68
70In some situations, asking for the exact date might be overly specific and unnecessary. For instance, a food delivery service might benefit from quick shortcuts to “tonight,” “tomorrow morning” or “Monday,” rather than a calendar overlay. Museum website could offer tickets for the next few days (“today,” “tomorrow,” “weekend”) and a calendar overlay for more precise input. In fact, you could explore most frequently used timeframes and suggest quick shortcuts to the most common selections.
73The National Geographic schedule page76 highlights shows prominently, grouping them by time. A little switcher in the left upper corner switches between daily and weekly views. The mobile view is not available, but it could easily display daily view on mobile (by default), with an option to switch to weekly view, and the other way around on desktop. Common selections (“Early morning”, “Morning”, “Afternoon”, “Primetime”) are extracted from the time picker — a precise input isn’t necessary.
If your date input should be even fuzzier than above, or your customers sometimes don’t have a specific date in mind, a date picker should probably be the method of last resort. More often than not, a couple of presets and general suggestions, combined with filters, would work way better than browsing months and years ever would.
In that case, you could still provide a detailed calendar view, displaying all options at once, and using color coding, for example, to indicate best prices. In fact, that’s what Google Flights7977 displays when flexible dates are selected. However, the option is dropped on narrow screens altogether.
78Dohop888581, on the other hand, uses not only flexible dates but also flexible location as the main feature, prominently highlighting both features as the user starts typing in their destination or date. Instead of the price, the calendar view highlights the availability of direct and indirect flights, as well as whether there are flight days with no connections (based on the user’s defined departure days, for example).
82
84
87Just like any other input, a date input can also be accomplished by moving the knob of a slider. The good ol’ slider can be used either for a single value input or to specify a date range, and indeed it’s often featured in interfaces where the customer can set a predefined range of dates.
A discussion of sliders deserves another article, but the main problem is that too often they just don’t allow for precise enough input90. The wider or the denser the range selectable through a slider, the harder it is to use. In usability tests, you’ll see users desperately try to set the exact date in a slider by moving the knob very carefully and very slowly. If we think about the date or time range — which can vary a lot, and encompass months or a wide range of time slots — then picking one of the options can become quite an adventure on narrow screens.
Sliders seem to work best when the specific value does not matter much, or when you have a very limited set of options to scrub through. Unfortunately, it won’t be the case for most date pickers, especially when the date is adjusted and refined quite frequently.
91At this point, you might be wondering whether all of that effort and all of these considerations are actually worth it. Why not use native93date94pickers95 — isn’t that exactly what they are intended for? Besides, because they are native, they will look and behave consistently with the user’s expectations anyway.
The problem with native date pickers is that they are very limited in their design and functionality. For example, it’s impossible to add any details such as availability or pricing to a native date picker to avoid zero-results pages. It’s also impossible to select a date range and highlight the connection between two dates because it doesn’t provide a calendar overview.
96Just like with regular numerical input, the starting point and end point require two separate date pickers. Scrolling through dates is predictable and consistent, but because selection requires precision, they become very annoying very quickly in usability interviews. Also, native date pickers aren’t supported in desktop browsers, and so you still would need to design the experience for larger views, essentially transforming a <select> menu into a calendar overlay anyway.
Does it mean that using a native control is always a bad idea? Not at all. If the date input in your case is faster with native controls, and you don’t need a calendar view, then using a native date picker is absolutely reasonable. In fact, while numerical input might have formatting issues due to differences in day formats, the user is more likely to provide proper data quickly this way because native controls cater to the user’s mobile device. However, whenever you need slightly more than just an exact and “stable” date, such as a birthday, then native date pickers seem to hit their limitations quite quickly.
Things get slightly more complicated when, in addition to a date picker, you also need to provide a time-slot picker. The easiest way to achieve time selection would be by providing an extra input field as a step after the date has been selected. This brings us back to square one again: That input field could support manual input, or contain a mini-stepper, or prompt a custom drop-down, or appear as a slider or be a native <select> menu.
97
100But what if we look at this issue from a slightly different perspective? Now, a typical example of an interface with a time picker would be booking an appointment or a restaurant reservation. In these cases, both the date and time matter, but sometimes the date matters a bit more, whereas other times, time matters a bit more. One thing is certain, though: Choosing a date isn’t helpful if there are no appropriate time slots on that day. Wouldn’t it be more reasonable, then, to ask for the time slot first, just to display all available days with the time in question (or closest slots) for quicker selection? In that case, time selection acts as a filter to remove all unavailable days.
102In fact, when it comes to appointments, a good number of users have a certain time slot in mind, because the day might be packed with work time and family matters. The selection of time, then, can’t be a radio button, but rather a multi-select group, allowing for various options at once.
104In fact, that’s exactly the idea that Matthew Talebi suggested107 recently. Prompt the customer to select the time range that best fits their schedule (morning, afternoon or evening), and display next available appointments in a list, available for booking.
Alternatively, you could combine date and time selection in one screen as well. On Treatwell.nl108, customers can slide through the days horizontally while the list of available time slots appears horizontally — with the price displayed inline. That’s a slightly more compact way to combine date and time pickers in one place — and it’s quite common in TV guides as well.
109
110Envy.rent114112 extends its date picker with a slider for selecting an approximate time slot to pick up a rented car. A precise slot doesn’t matter much in that case, but a group of checkboxes would do the job here as well.
113The Calendars 5116 app uses a sort of tabbed navigation to switch between date and time selection. The panel at the bottom is easily accessible for the thumb. The time view, though, has a very unusual layout for time selection, with options grouped by daytime and nighttime, and minutes listed in a slider, basically resulting in 36 clickable buttons. A slightly better way to provide exact input would be to use a native control or progressive disclosure, where we could display only AM or PM first, and then allow users to dive into specific hour or minute input if needed.
117
119If your problem is very specific, you might explore alternative designs altogether — the date-picker overlay doesn’t have to contain a calendar view, but could rather be a group of pre-defined buttons to “construct” the date. Alternate Date Picker122 is designed with the goal to provide the easiest way to define a date from very wide range of dates (1800–2999). The selection doesn’t require keyboard input, nor does it prompt a calendar overlay or slider. You just tap on buttons to build the date. (Thanks to Slav for heads up in the comments!)
123Localization matters. Whether you are using a date input or time input, it’s critical to have some sort of strategy of how you will target specific regions of the world to avoid misbookings. You could use a combination of drop-down and numerical input to minimize the number of mistakes made, like Gmail130125 and Yahoo132126 do for input fields. But at least when it comes to the calendar view of weeks, you’ll need to dynamically switch between US-formatted dates and EU-formatted dates, for example — and potentially consider Hijri, Hebrew, Chinese and your user base-specific calendars in addition to Gregorian calendar as well. You can always check the Date Format By Country Wikipedia page127 as a reference as well.
128
129
131Making one of those date pickers accessible isn’t trivial, because date selection should be keyboard-accessible and you would need to toggle between open and collapsed states. You can find an overview of accessible date pickers133. Also, consider looking into Whatsock’s examples134.
Looking back now, what can we do with a date picker? We can combine day, month and year into one input field, add a fancy calendar icon, and prompt a calendar overlay that exposes the main purpose of the calendar prominently. We could use smart inputs, a mini-stepper and flexible dates, and we could allow users to switch between week and month views or change the level of fidelity of the calendar accordingly.
We could even consider two separate views — a big-picture calendar along with a detailed list. The transition from start date to end date should be seamless and should happen without prompting a second calendar, just with a few taps. Typing in an input field might be less annoying than scrolling through the select wheeler or jumping back and forth between months and years. And to help users find the perfect day, we can expose the most relevant detail, such as availability or pricing, in the calendar as well.
If you’re about to design a date picker, here are all of the questions you might have to ask yourself in order to choose the right solution for your problem:
If the date is likely to be quite far in the past or the future (for example, when booking a vacation), a numerical input with a date picker might be a good option. If the date input range is usually quite short (less than six weeks, such as when booking a medical appointment), definitely consider adding a mini-stepper for quicker jumps.
Ideally, providing numerical input, a calendar overlay and a mini-stepper seems to be a safe bet, as long as numerical input is reliable enough.
And that’s a wrap! Perhaps you had very different experiences than the ones mentioned in the article? Let us know in the comments to this article! Also, if you have another component in mind that you’d love to have covered, let us know, too — we’ll see what we can do!
This article is part of the new ongoing series about responsive design patterns here on yours truly, Smashing Magazine. We’ll be publishing an article in this series every two weeks. Don’t miss the next one — on fancy (and not so fancy) responsive car configurators sliders. Interested in a (printed) book covering all of the patterns, including the one above? Let us know in the comments, too — perhaps we can look into combining all of these patterns into one single book and publishing it on Smashing Magazine. Keep rockin’!
(al yk il)
Fractures * Numi * Attract hover effect * sqlify * Gatsby * Remote Starter Kit * ImageOptim Sketch Plugin * Pe…
What comes to your mind when you hear the word “business”? White collars, cubicle offices, and encrusted habits? Not when you ask the folks at Vexels161. Their Business Concept icon set manages to break free from the conceptions that are stuck in our heads and paints a fresh and creative picture instead. One that captures the liveliness of today’s startup world. And, well, we are very happy to present you the icons as a freebie.
Colorful, friendly, but nonetheless straight to the point, that’s Vexels’ take on the business subject. There are 28 icons in the set in total, depicting concepts that help a business thrive — from vision and strategy to teamwork and competition. All icons are available in AI, EPS, SVG, PSD, and PNG formats.
Please note that this icon set is released under a Creative Commons Attribution 3.0 Unported4 license. This means that you may modify the size, color, and shape of the icons. Attribution is required, so if you would like to use the icons, please do remember to credit the designers and to link to this article if you want to spread the word in blog posts or anywhere else.
9
11
13“We view business as an opportunity to work with talented people, to grow and help each other out while making a great product in the process. We created this icon collection because of it. This pack is colorful and lively, it’s a set where competition isn’t seen like the enemy and creativity and innovation have an important role.”
A big thank you to the folks at Vexels161 for designing this wonderful icon set — we sincerely appreciate your time and efforts! Keep up the fantastic work!
Apple’s Worldwide Developer Conference (WWDC) has been running for 34 years, which is 6 years longer than The Simpsons. Like Netflix, Apple likes to drop a whole season at once. When it does, I devote that week and the following weekend to binge-watching as many videos as I can and trying out some of the new technology, especially as it relates to iOS.
In the past 10 years, a big portion of these conferences has been devoted to iOS. This is where we learned about the first iPhone SDK, notifications, share and today widgets, the iOS 7 redesign, iPad multitasking, and other iOS milestones. I was genuinely surprised with some of the announcements this year.
Here’s my overview of what happened this WWDC season, with code samples. But before we begin, there are some things you need to keep in mind. If you want to try out any of the sample projects, you are going to have to update your Mac to macOS Sierra 10.12.5 (the latest point release), and have Xcode 9 installed. If you are super-brave, or just irresponsible, you’ll need at least one device on iOS 11 for some of the samples to work. I fall under the irresponsible category here, but I also needed iOS 11 for my day job and to write this article, which seemed like a good excuse, but it’s not. Everything is working fine for me so far, but this is a huge risk. Don’t do it with an unbacked-up device you care about.
While you are waiting for Xcode 9 to download, go watch the WWDC Keynote9 if you haven’t seen it. If you have, watch the “Platforms State of the Union4510.” All WWDC session videos have to viewed in Safari or in the WWDC app on any iOS or tvOS device. Another great option is the unofficial WWDC app for macOS11.
This article is about the WWDC updates that matter most to iOS developers, so I’ll skim through some of the big news on other fronts.
13That’s a lot, and we haven’t even gotten to the new developer capabilities in iOS 11.
Every year, iOS developers can expect some refinements to the overall system experience, and this year we got a big one: drag and drop. A lot of app developers try to do this themselves, but now iOS provides built-in support for it that supports multi-select, default animations and standardized interactions. On iPad, it even works between apps. You could say it was overdue, and perhaps it was, but we didn’t even get copy-and-paste until iPhone OS 3.
Another big addition to the system is that files are now more of a first-class concept. You can browse your device’s documents in the Files app (which includes cloud-based documents from iCloud Drive and third-party services), but, also, any app can bring up a file browser for the user to pick files from.
You can see these and more in the “What’s New in Cocoa Touch4617” session.
The new drag-and-drop system interaction is implemented so that any view can participate by having a UIDragInteraction attached to it and then implementing the appropriate delegates. Similarly, the drop target just needs to implement the drop delegates to accept the dragged data. On iPad, items can be dragged from one app to another, but on iPhone, drag and drop only works inside the same app.
One nice thing is that if a view already knows how to accept pasted data, then it automatically will accept drops of the same kind. So, UITextView can automatically have text dropped onto it without your needing to add anything to your app. You can get the basics by watching the “Introducing Drag and Drop18” video or downloading the demo app19.
If you want to add drag or drop behaviors to a UITableView or UICollectionView, then a lot of the work is done for you already, and you just need to implement the drag or drop delegates specific to those views. The details can be found in the “Drag and Drop With Collection and Table View20” video and demo app21.
The UICollectionView/UITableView Drag and Drop Demo app implements a photo album that supports using drag and drop to:
The main points to look at are in PhotoCollectionViewController.swift in the sample app (which you can download22):
A UIViewController with a collection view should implement the UICollectionViewDragDelegate to allow drags and the UICollectionViewDropDelegate to allow drops.
class PhotoCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDragDelegate, UICollectionViewDropDelegate {
As with other delegates, you should assign the collection view’s drag and drop delegates to self in viewDidLoad.
collectionView?.dragDelegate = self collectionView?.dropDelegate = self
The only required drag delegate protocol method is called to create a UIDragItem array when dragging starts. A drag item holds any object that represents the drag data.
func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] { let dragItem = self.dragItem(forPhotoAt: indexPath) return [dragItem] }
On the drop side, you need to say whether you can accept the data being dragged over you:
func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool { guard album != nil else { return false } return session.hasItemsConforming( toTypeIdentifiers: UIImage.readableTypeIdentifiersForItemProvider) }
In this case, we return true if the dragged item can be turned into an image.
Once the drop actually happens, we need to copy or move the photos into the collection view.
func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator) { guard album != nil else { return } let destinationIndexPath = coordinator.destinationIndexPath ?? IndexPath(item: 0, section: 0) switch coordinator.proposal.operation { case .copy: // Receiving items from another app. loadAndInsertItems(at: destinationIndexPath, with: coordinator) case .move: move(items: coordinator.items, with: coordinator) default: return } }
There are entry points for customizing the lift and drop animations, and for moving items out of the way, and a lot of other possibilities. Many of the optional features are implemented in the sample app, and more details were covered in the “Mastering Drag and Drop23” session. You could also read the “Drag and Drop5224” documentation.
If your iOS app is also available as a mobile web app, then you can get access to the user’s website credentials to let them log into your app automatically.
To support pre-iOS 11 features (such as universal links25), you probably already have an apple-app-site-association file to connect your website and app (if not, you should do that). All you need to do in addition is set the content type of your username and password UITextFields to .username and .password, respectively.
self.userNameField.textContentType = .username self.passwordField.textContentType = .password
Then, when you show a log-in screen, iOS will offer to fill it in with the user’s saved credentials.
26More details can be found in the “Introducing Password AutoFill for Apps27” session.
The new Files app lets users browse files directly, but if your app needs files from other apps, you can bring up a document-picker view, similar to how you would have used an image picker to get a photo from the Photos app.
let docs = UIDocumentBrowserViewController(forOpeningFilesWithContentTypes: [kUTTypePDF]) docs.delegate = self // implement UIDocumentBrowserViewControllerDelegate self.present(docs, animated: true)
To process the chosen document, implement this UIDocumentBrowserViewControllerDelegate protocol method:
func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) { // process document here }
The session “File Provider Enhancements28” covers this in more detail.
Swift 4 is open-source, so most of what’s happening in it can be seen in the mailing list and GitHub repository. One thing that was shown at WWDC is the new Codable protocol, which allows structs to be encoded via the NSCoding classes. All you need to do is declare conformance to the Codable protocol, and Swift will give you a default implementation, like so:
struct WWDCVideo : Codable { let title: String let presenters: [String] let videoURL: URL }
This gets you automatic JSON support. You encode a struct like this:
let swiftVideo = WWDCVideo( title: "What's New in Swift", presenters: [ "Doug Gregor", "Bob Wilson", "Ben Cohen", "John McCall", ], videoURL: URL(string: "https://developer.apple.com/videos/play/wwdc2017/402/")! ) let jsonData = try JSONEncoder().encode(swiftVideo)
And you decode with this:
let vid = try JSONDecoder().decode(WWDCVideo.self, from: jsonData)
Also, Codable supports custom encoding and decoding if you need it, and it supports an easy way to make simple alterations, like alternate key names (see CodingKeys).
For more on what’s happening in Swift, see “What’s New in Swift29.”
One big theme of WWDC was how Apple is using machine learning (ML) to add features across the system and apps. The Siri watchface at the top of the keynote was the first example, but Apple announced so many ML-based features that it was not a surprise when it introduced CoreML, a new Apple framework that implements the run phase of ML models, such as neural networks.
At a very high level, machine learning is used to implement functions that map arbitrary inputs to arbitrary outputs. Instead of the mapping being coded directly, it’s learned from sample data. In iOS, machine learning has been used to implement facial recognition, OCR, handwriting recognition, typed-text prediction, Siri and a lot of other features.
The first thing that CoreML does is define a machine-learning-model file specification. This file is something you create ahead of time by using training software to describe your model and feeding it a lot of examples of inputs and the expected outputs. Over time, the software will be able to predict the outputs for new inputs. This understanding can be exported to model files to be used in other programs that can run models.
Once you drag a model file into your Xcode project, a Swift class is created for you that exposes a simple function that you can use to run the model on your input.
A common form of ML input is an image (from the camera, for example), and a common output is a rectangle of a recognized region in the photo. It might look something like this:
let kittenFinder = KittenFinder() let r: CGRect = kittenFinder.findKitten(image: imageView.image)
The exact interface is generated from your model file. When you call it, all kinds of things are taken care of for you. For example, models based on images usually need a specific size and pixel format (color or grayscale). CoreML will automatically convert whatever image you send it to whatever the model actually needs (and supports all of the ways an image can be represented in iOS).
Using the model is extremely simple. Making these models is left as a exercise to the developer, but there are actually a lot of open-source ones, and Apple has made some available30 for you to use in your apps. The model format’s specification is open, and there’s an open-source Python library to help you convert31 other formats to it. It’s likely that the ML community will make more models available in this format in the coming months.
There’s a lot more in the “Introducing Core ML32” session and in the CoreML developer documentation33.
But Apple didn’t stop there. On top of CoreML, It wrote two more frameworks that make some common tasks even easier. The Vision framework assumes that you want to recognize objects in a live camera stream, and it can read AVCaptureSession images automatically. It also builds in some models, such as a more accurate face detector that can also give you the location of “face landmarks” (for example, eyes, nose, mouth).
There is no sample app or documentation for detecting faces yet, but I was able to piece something together from what Apple showed in the Vision session (get it on GitHub34).
In a typical AVCaptureSession-based app, add the Vision import to your View Controller
import Vision
And add this property to make detection requests:
var requests: [VNDetectFaceRectanglesRequest] = []
Initialize it in this function, which you should call in viewDidLoad:
func setupVision() { let faceDetectionRequest = VNDetectFaceRectanglesRequest(completionHandler: self.handleFaces) self.requests = [faceDetectionRequest]; }
In your captureOutput implementation, add this code:
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } // Make the Face Detection Request var requestOptions: [VNImageOption: Any] = [:] if let cameraIntrinsicData = CMGetAttachment(sampleBuffer, kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, nil) { requestOptions = [.cameraIntrinsics: cameraIntrinsicData] } // The orientation should be determined from the phone position, but assume portrait (1) for now let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer:imageBuffer, orientation: 1, options: requestOptions) do { try imageRequestHandler.perform(self.requests) } catch { // handle this }
When a face is detected, this function will be called:
func handleFaces(request: VNRequest, error: Error?) { DispatchQueue.main.async { self.hideFaceBox() guard let result = (request.results as? [VNFaceObservation])?.first else { return } let bb = result.boundingBox if let imgFrame = self.imageView?.frame { // Bounding Box is a 0..<1.0 normlized to the size of the input image and // the origin is at the bottom left of the image (so Y needs to be flipped) let faceSize = CGSize(width: bb.width * imgFrame.width, height: bb.height * imgFrame.height) self.drawFaceBox(frame: CGRect(x: imgFrame.origin.x + bb.origin.x * imgFrame.width, y: imgFrame.origin.y + imgFrame.height - (bb.origin.y * imgFrame.height) - faceSize.height, width: faceSize.width, height: faceSize.height) ) } } }
The request passed in has a results array. We grab the first element and turn its bounding box into a frame for a semi-transparent view to show over the captured image. The main thing to note is that the coordinate system of the bounding box puts the origin in the bottom-left, whereas the iPhone puts the origin in the top-left, so we need to flip the Y coordinate.
The full app is available on GitHub35.
Here is me running the device pointing at my laptop showing a picture of Tim Cook:
See the “Vision Framework: Building on CoreML36” session for details, or read the Vision documentation37.
There’s also a natural language processing (NLP) library, which didn’t seem as useful to me, but it can detect languages and label parts of speech in a text input. The core parts could be used to implement something like a predictive text engine in a keyboard, but that’s not built into the framework.
See all of the details in “Natural Language Processing and Your Apps38.”
All CoreML frameworks are on device, which means:
The similar features from cloud services tout much higher accuracy and training based on enormous data sets, which continue to grow. Your CoreML model is baked in at compile time. If you get more data, then you’ll need to retrain your model, import it and rebuild.
The final big announcement was ARKit, a new framework for adding augmented reality to your app. If you have been building any content using SceneKit (for 3D games) or SpriteKit (for 2D), then you are in a good position to take advantage of ARKit, because it integrates with their drawing surfaces. Incorporating your existing code into an AR version of your app doesn’t take much.
To get you started quickly, Xcode now has an augmented-reality app template:
39If you choose this, then on the next screen, you are given a choice of content technology (SceneKit, SpriteKit or Metal). Choose SceneKit, and the app will be ready to run.
The default code places a spaceship floating in front of you. You can walk around and examine it. Because this is all built on SceneKit, adding in your 3D models is simple if you have them. Just import one and update this line:
let scene = SCNScene(named: "art.scnassets/ship.scn")! sceneView.scene = scene
But to play around, you can generate 3D geometry with SceneKit’s various geometry nodes. For example, replace the above two lines with this:
self.sceneView.autoenablesDefaultLighting = true let scene = SCNScene() let sphereNodes = SCNNode() scene.rootNode.addChildNode(sphereNodes) addSphere(to: sphereNodes, pos: SCNVector3Make(0, 0, -2.0)) addSphere(to: sphereNodes, pos: SCNVector3Make(-0.3, 0.2, -2.4)) addSphere(to: sphereNodes, pos: SCNVector3Make(0.3, 0.2, -2.8))
The AR template turns off default lighting in the storyboard, but we want our spheres to appear to be lit by the light that ARKit detects in the scene. All of the coordinates are in real-space coordinates of 1 meter, and the negative z-axis is in front of us, so this places 3 spheres about 2 meters or so in front of our starting position.
Then, add this function to create and add a sphere to the scene:
func addSphere(to node: SCNNode, pos: SCNVector3) { let sphere = SCNSphere(radius: 0.1) let sphereNode = SCNNode(geometry: sphere) sphereNode.position = pos node.addChildNode(sphereNode) }
When you run it, it will look like this:
ARKit can also detect surfaces and lets your nodes interact with them. Check out the “Introducing ARKit: Augmented Reality for iOS41” session for details. Apple’s Developer website also has documentation for ARKit42.
Even with all of this, there was so much more. Xcode 9 is a big upgrade, with a fully rewritten editor and (finally) support for refactoring in Swift. You can run multiple simulators and even debug wirelessly (much needed for AR debugging).
There’s more support for right-to-left languages and easier ways to deal with dynamic type sizes.
Swift Playgrounds got two updates. One you can download now, but the beta for version 2.0 is also available through TestFlight43. This new version lets you play with all of iOS 11’s features, such as ARKit and Swift 4.
Normally, we expect the real release of all of this sometime in September, along with new iPhones, so go watch those videos and get your apps ready for iOS 11.
(da, vf, al, il)
If you are into Microsoft’s UWP Design and use React, this might be interesting for you.
https://www.minds.com/ is what started this all…
1. Navigate to the Facebook website and log in to your account.
2. Click the “Find Friends” link located next to your account name on the Facebook menu.
3. Enter the name of an employer in the “Employer” field.
4. Select the correct employer from the search results that appear.
5. Click the “Add Friend” button located next to any of the people listed in the results for that company or click the person’s name to view his public personal Timeline.
Finally, if you run across folks online you want to know more about often, search a ton of engines for someone’s name with the Who Is This Person? Firefox extension. Simply highlight the name on any web page and look ’em up on Wink, LinkedIn, Wikipedia, Facebook, Google News, Technorati, Yahoo Person Search, Spock, WikiYou, ZoomInfo, IMDB, MySpace and other engines from the Who Is This Person? context menu item.
For more online sleuthing resources, check out Wendy’s great tutorial on searching public records online. To make yourself more findable? Have a say in what Google says about you. Also, many of these services let you “claim” your name and add information to your results. Do a search for your own name and click the link that says, in effect, “Is this you?”