Web Standards

Would You Watch a Documentary Walking Through Codebases?

Css Tricks - Tue, 01/22/2019 - 9:15am

This resonated pretty strongly with people:

I’d watch a documentary series of developers giving a tour of their codebases.

— Chris Coyier (@chriscoyier) January 6, 2019

I think I was watching some random Netflix documentary and daydreaming that the subject was actually something I was super interested in: a semi-high-quality video deep dive into different companies codebases, hearing directly from the developers that built and maintain them.

Horror stories might also be interesting. Particularly if they involve perfect storm scenarios that naturally take us on a tour of the codebase along the way, so we can see how the system failed. We get little glimpses of this sometimes.

Probably more interesting is a tour of codebases when everything is humming along as planned. I wanna see the bottling factory when it's working efficiently so I can see the symphony of it more than I wanna see a heaping pile of broken glass on the floor.

Or! Maybe the filmmaker will get lucky and there will be some major problem with the site as they're filming, and they can capture the detection, reaction, and fixing of the problem and everything that entails. And sure, this isn't wildlife rescue; sometimes the process for fixing even the worst of fires is to stare at your screen and type in silence like you always do. But I'm sure there is some way to effectively show the drama of it.

I'm not sure anything like this exists yet, but I'd definitely watch it. Here's a bunch of stuff that isn't a million miles away from the general idea:

The post Would You Watch a Documentary Walking Through Codebases? appeared first on CSS-Tricks.

Netlify Makes Deployments a Cinch

Css Tricks - Tue, 01/22/2019 - 8:56am

(This is a sponsored post.)

Let's say you were going to design the easiest way to deploy a static site you can possibly imagine. If I was tasked with that, I'd say, well, it would deploy whenever I push to my master branch, and I'd tell it what command to run to build my site. Or maybe it has its own CLI where I can kick stuff out with as I choose. Or, you know what, maybe it's so accommodating, I could drag and drop a folder onto it somehow and it would just deploy.

Good news: Netlify is way ahead of me. Netlify can do all those things, and so much more. Your site will be hosted on a CDN so it's fast as heck. You can roll back to any other deployment because each build is immutable and trivially easy to point to. You can upload a folder of Node JavaScript functions and you can run those so you can do back-end things, like talk to APIs securely. Heck, even your forms can be automatically processed without writing any code at all!

It's almost shocking how useful Netlify is. I recommend giving it a try, it might be just that empowering tool you need to build that next project you have in mind. 🤔

Direct Link to ArticlePermalink

The post Netlify Makes Deployments a Cinch appeared first on CSS-Tricks.

The Secret Weapon to Learning CSS

Css Tricks - Tue, 01/22/2019 - 5:10am

For some reason, I’ve lately been thinking a lot about what it takes to break into the web design industry and learn CSS. I reckon it has something to do with Keith Grant’s post earlier this month on a CSS mental model where he talks about a “common core for CSS”:

We need common core tricks like this for CSS. Not “tricks” in the old sense (like how to fake a gradient border), but mental patterns: ways to frame the problem in our heads, so we can break problems into their constituent parts and notice recurring patterns. Those of us who deeply understand the language do this internally. We need to start working on distilling out these mental patterns we use for understanding layout and positioning and working with relative units, so that we can articulate them to others.

On this note, Rachel Andrew also wrote about how to learn CSS, but in this case, she focuses more on technical CSS specifics:

For much of CSS, you don’t need to worry about learning properties and values by heart. You can look them up when you need them. However, there are some key underpinnings of the language, without which you will struggle to make sense of it. It really is worth dedicating some time to making sure you understand these things, as it will save you a lot of time and frustration in the long run.

This ties in nicely with Andy Bell's "CSS doesn’t suck" argument. Andy says that perhaps the reason why people attack CSS so often is because they simply don’t fundamentally understand it and thereby don’t respect why it works the way it does:

It’s getting exhausting spending so much of my time defending one of the three pillars of the web: CSS. It should sit equal with HTML and JavaScript to produce accessible, progressively enhanced websites and web apps that help everyone achieve what they need to achieve.

As I read these and other posts, I couldn’t stop thinking about the advice that I would give to a fledgling developer who's interested in web design and CSS—where would I recommend that they start? There’s so much to cover that merely thinking about it gives me a headache.

Personally, I often start with the basics of HTML and slowly introduce folks to CSS properties like color or font-family. But this sort of advice is generally only useful if you’re sitting right next to someone and have the time to explain everything about HTML and CSS: how to lay out a page, how to handle performance, how to think about progressive enhancement, etc. These topics alone are worthy of a month-long workshop—and that’s only the beginning!

Where to get started then? What sort of advice would help a student in the long run?

My experience in the industry probably matches that of a lot of other web designers: I didn’t go to school for this. I figured things out by myself while using referential sites like CSS-Tricks and Smashing Magazine to fill in the gaps. I would start with a project (like making a website for my high school band—and no, I will tell you the name of it), and in the process, I would haphazardly learn about typesetting, Sass, build tools, as well as accessible, hand-written markup.

Hear me out, but I don’t think the best way to get started in the web design industry is to learn the latest doodad or widget. Yes, you’ll have to get to that eventually. Or maybe not. At some point, getting a firm handle on flexbox and grid and memorizing a few properties is a good thing to do. But I want to teach web designers to fish and make sure that they can set themselves up for the future. And the best way to fish for CSS probably won't be found in a particular book or classroom curriculum. Instead, I think it’s best to recommend something else entirely.

My advice can be summarized in just four words: Get an RSS reader.

After thinking about this, I figured out that the most useful advice I can give is to get involved with the community—and, for me, that has been via RSS. Find a ton of blogs and subscribe to them. Over time, you’ll not only learn about the craft, but have a hefty (and hopefully organized) set of resources that cover basics, tricks, standards, personal struggles, and news, among many, many other things.

This is still how I learn about web design today. RSS is the most important tool I have to help me continue learning about the web—from working with tiny CSS properties to giant frameworks. Sure, Twitter is a good place to learn from (and even connect with) heavy hitters in the web design industry quickly, but there’s no better technology than RSS to constantly keep yourself informed of how people are thinking about CSS and web development.

With that, I encourage you (yes, you) to get an RSS reader if you don't already have one, or dust off the one you do have if it's been a while. I use Reeder 3 on OSX and iOS and pair that with Feedbin. From there, subscribe to a ton of blogs or follow a lot of folks on Twitter to find their websites. There's no shortage of material or sources out there!

This sounds like a silly thing to recommend but fitting yourself into the web design community is more important than learning about any cool CSS trick. You’ll be creating an environment where you can constantly learn new things for the future. And I promise that, once you start, finding people who care about web development and, ultimately, learning about CSS, isn’t as intimidating as it could be on your own.

Which websites should you subscribe to? Well, Stuart Robson made a wonderful list of all the websites that he subscribes to via RSS—you should be able to download that file and drop it straight into your RSS reader. Also, Rachel Andrew made a great list of websites a while back when she asked what’s happening in CSS? And of course our very own newsletter, This Week in Web Design and Development, is certainly a good place to start, too. Speaking of email and newsletters—Dev Tips by Umar Hansa is another great resource where I’m constantly learning new things about Chrome’s DevTools.

What websites do you like though? What’s the best resource for keeping up with CSS? Let us know in the comments below!

The post The Secret Weapon to Learning CSS appeared first on CSS-Tricks.

Who is @horse_js?

Css Tricks - Tue, 01/22/2019 - 5:09am

Many of us follow @horse_js on Twitter. Twenty-one thousand of us, to be exact. That horse loves stirring up mischief by taking people's statements out of context. It happened to me a few times and almost got me in trouble.

I wonder how many people hate CSS because their experience with it

— Horse JS (@horse_js) September 23, 2018

I wonder how many people hate CSS because their experience with it is overriding bootstrap.

In completely unrelated news, guess what I'm doing today.

— Sarah Drasner (@sarah_edo) September 21, 2018

There's even a @horsplain_js account that follows along and explains the origin of the tweets.

Burke Holland and Jasmine Greenaway created a data science project to uncover the true identity of the notorious JavaScript parody account. This single page site goes through time series analysis, most quoted people, location and phrases to get to the bottom of the riddle. We won't spoil it... you'll just have to visit and see.

Direct Link to ArticlePermalink

The post Who is @horse_js? appeared first on CSS-Tricks.

The Great Divide

Css Tricks - Mon, 01/21/2019 - 6:48am

Let’s say there is a divide happening in front-end development. I feel it, but it's not just in my bones. Based on an awful lot of written developer sentiment, interviews Dave Rupert and I have done on ShopTalk, and in-person discussion, it’s, as they say... a thing.

The divide is between people who self-identify as a (or have the job title of) front-end developer, yet have divergent skill sets.

On one side, an army of developers whose interests, responsibilities, and skill sets are heavily revolved around JavaScript.

On the other, an army of developers whose interests, responsibilities, and skill sets are focused on other areas of the front end, like HTML, CSS, design, interaction, patterns, accessibility, etc.

Let’s hear from people who are feeling this divide.

In response to our post, "What makes a good front-end developer?", Steven Davis wrote:

I think we need to move away from the term myself. We should split into UX Engineers and JavaScript Engineers. They are different mindsets. Most people are not amazing at both JavaScript and CSS. Let UX Engineers work closely with UX/Design to create great designs, interactions, prototypes, etc. and let JavaScript Engineers handle all the data parts.

So sick of being great at CSS but being forced into JavaScript. I'm not a programmer!

This schism isn't happening under our feet. We're asking for it.

I heard it called an identity crisis for the first time in Vernon Joyce's article, "Is front-end development having an identity crisis?" He points to the major JavaScript frameworks:

Frameworks like Angular or libraries like React require developers to have a much deeper understanding of programming concepts; concepts that might have historically been associated only with the back end. MVC, functional programming, higher-order functions, hoisting... hard concepts to grasp if your background is in HTML, CSS, and basic interactive JavaScript.

This rings true for me. I enjoy working with and reading about modern frameworks, fancy build tools, and interesting data layer strategies. Right now, I'm enjoying working with React as a UI library, Apollo GraphQL for data, Cypress for integration testing, and webpack as a build tool. I am constantly eying up CSS-in-JS libraries. Yet, while I do consider those things a part of front-end development, they feel cosmically far away from the articles and conversations around accessibility, semantic markup, CSS possibilities, UX considerations, and UI polish, among others. It feels like two different worlds.

When companies post job openings for "Front-End Developer," what are they really asking for? Assuming they actually know (lolz), the title front-end developer alone isn't doing enough. It's likely more helpful to know which side of the divide they need the most.

Who gets the job? Who's right for the job? Is the pay grade the same for these skill sets?

My hope is that the solution is writing more descriptive job postings. If clearly defined and agreed upon job titles are too much of an ask for the industry at large (and I fear that it is), we can still use our words. Corey Ginnivan put it well:

I'd love more job descriptions to be more vulnerable and open — let people know what you want to achieve, specify what they'll be working on, but open it as a growth opportunity for both parties.

This seemed to work pretty well for us at CodePen. Our own Cassidy Williams said she really appreciated this writeup when Rachel Smith sent it to her to consider.

"Front-end developer" is still a useful term. Like Mina Markham described to us recently, it's who people that primarily work with browsers and people using those browsers are. But it's a generic shorthand, says Miriam Suzanne:

Front-end developer is shorthand for when the details don't matter. Like being in an indie-rock band — who knows what that is, but I say it all the time. Shorthand is great until you're posting a job description. When the details matter, we already have more detailed language — we just have to use it.

To put a point on this divide a bit more, consider this article by Trey Huffine, "A Recap of Frontend Development in 2018." It's very well done! It points to big moments this year, shows interesting data, and makes predictions about what we might see next year. But it's entirely based around the JavaScript ecosystem. HTML is only mentioned in the context of JavaScript-powered static site generators and CSS is only mentioned in the context of CSS-in-JS. It's front-end development, but perhaps one half of it: the JavaScript half. If you read that summary and don't connect with much in there, then my advice would be:

That's OK. You can still be a front-end developer. 🙏

You might be exploring layout possibilities, architecting a CSS or design system, getting deep into UX, building interesting animations, digging into accessibility, or any other number of firmly front-end development jobs. There's more than enough to go around.

Remember just last last year how Frank Chimero, who builds incredibly great websites for himself and clients, was totally bewildered with where front-end development had gone? To summarize:

... other people’s toolchains are absolutely inscrutable from the outside. Even getting started is touchy. Last month, I had to install a package manager to install a package manager. That’s when I closed my laptop and slowly backed away from it. We’re a long way from the CSS Zen Garden where I started.

A long way indeed. I might argue that you don't have to care. If you've been and continue to be successful building websites any way you know how for yourself and clients, hallelujah! Consider all this new toolchain stuff entirely as an opt-in deal that solves different problems than you have.

And yet, this toolchain opaqueness prods at even the people necessarily embedded in it. Dave Rupert documents a real bug with a solution buried so deep that it's a miracle it was rooted out. Then he laments:

As toolchains grow and become more complex, unless you are expertly familiar with them, it’s very unclear what transformations are happening in our code. Tracking the differences between the input and output and the processes that code underwent can be overwhelming.

Who needs these big toolchains? Generally, it's the big sites. It's a bit tricky to pin down what big means, but I bet you have a good feel for it. Ironically, while heaps of tooling add complexity, the reason they are used is for battling complexity. Sometimes it feels like releasing cougars into the forest to handle your snake problem. Now you have a cougar problem.

The most visible discussions around all of this are dominated by people at the companies that are working on these big and complex sites. Bastian Allgeier wrote:

Big team needs "x" that’s why "x" is the best solution for everyone. I think this is highly toxic for smaller teams with different requirements and definitions of what’s "maintainable" or "sustainable". I get in touch with a lot of smaller agencies and freelancers from all over the world and it's interesting how their work is often completely detached from the web’s VIP circus.

What is going on here? What happened? Where did this divide come from? The answer is pretty clear to me:

So big:

  • It's everywhere on the front end of websites. The major JavaScript front-end frameworks are seeing explosive growth and dominating job postings. These frameworks are used by loads of teams to power loads of websites. Native JavaScript is evolving quickly as well, which has lots of people excited.
  • It powers backends, too. Your site might be powered by or involve a Node.js server. Your build process is likely to be powered by JavaScript.
  • Third-party JavaScript powers so many front-end features, from a site's ad network and analytics to full-blown features like reviews, comments, and related content.
  • Concepts like Node-powered cloud functions, storage, and authentication, combined with low-cost and low-effort scalable hosting, have empowered the crap out of JavaScript-focused front-end developers. They can use their skills exclusively to ship entire functional products.

A front-end developer with a strong JavaScript skill set is wildly empowered these days. I've been calling it the all-powerful front-end developer, and I did a whole talk on it:

Through all the possibilities that swirl around the idea of serverless combined with prepackaged UI frameworks, a front-end developer can build just about anything without needing much, if any, help from other disciplines. I find that exciting and enticing, but also worthy of pause. It's certainly possible that you become so framework-driven going down this path that your wider problem-solving skills suffer. I heard that sentiment from Estelle Weyl who goes so far as to say she thinks of developers more as "framework implementers," reserving the title of engineer for tool-agnostic problem solvers.

This front-end empowerment is very real. Particularly in the last few years, front-end developers have gotten especially powerful. So powerful that Michael Scharnagl says he's seen companies shift their hiring in that direction:

What I am seeing is that many developers focus entirely on JavaScript nowadays and I see companies where they replace back-end developers with JavaScript developers.

What some don’t understand is that a JavaScript developer is not per se a front-end developer. A JavaScript developer may not like to write CSS or care about semantics. That’s the same way I prefer not to work directly with databases or configure a server. That’s okay. What is not okay is if you don’t want to use something and at the same time tell others what they do is easy or useless. Even worse is if you try to tell experts in their field that they are doing it all wrong and that they should do it your way.

And Jay Freestone takes a stab at why:

Over the last few years, we’ve started to see a significant shift in the role of the front-end developer. As applications have become increasingly JavaScript-heavy there has been a necessity for front-end engineers to understand and practice architectural principles that were traditionally in the domain of back-end developers, such as API design and data modeling.

It's happened even with my own small scale work. We were looking for a back-end Go developer to help evolve our web services at CodePen. When we didn't have a lot of luck finding the perfect person, we decided to go another direction. We saw that our stack was evolving into something that's extremely welcoming to JavaScript-focused front-end developers to the point where we could easily put more of them to work right away. So that's what we did.

There may be a cyclical nature to some of this as well. We're seeing coding schools absolutely explode and produce fairly talented developers in less than a year. These code school graduates are filling labor gaps, but more importantly, as Brad Westfall tells me, starting to lead industry discussions rather than be passive followers of them. And make no mistake: these schools are producing developers on the JavaScript side of the divide. Every single code school web development curriculum I've ever seen treats HTML/CSS/UI/UX/A11Y topics as early fundamentals that students breeze through or they are sprinkled in as asides while JavaScript dominates the later curriculum. Can you come in and teach our students all the layout concepts in three hours? When JavaScript dominates the conversations around the front end, it leads to some developers feeling inadequate. In a comment on Robin Rendle's "Front-end development is not a problem to be solved," Nils writes:

Maybe the term front-end developer needs some rethinking. When I started working, front-end was mostly HTML, CSS, and some JavaScript. A good front-end developer needed to be able to translate a Photoshop layout to a pixel perfect website. Front end today is much much more. If you want to learn front-end development, people seem to start learning git, npm, angular, react, vue and all of this is called front-end development.

I am a designer and I think I’m pretty good at HTML and CSS, but that's not enough anymore to be a front-end developer.

Robin himself gave himself the job title, Adult Boy That Cares Too Much About Accessibility and CSS and Component Design but Doesn’t Care One Bit About GraphQL or Rails or Redux but I Feel Really Bad About Not Caring About This Other Stuff Though.

It's also frustrating to people in other ways. Remember Lara Schenck's story of going in for a job interview? She met 90% of the listed qualifications, only to have the interview involve JavaScript algorithms. She ultimately didn't get the job because of that. Not everybody needs to get every job they interview for, but the issue here is that front-end developer isn't communicating what it needs to as an effective job title.

It feels like an alternate universe some days.

Two "front-end web developers" can be standing right next to each other and have little, if any, skill sets in common. That's downright bizarre to me for a job title so specific and ubiquitous. I'm sure that's already the case with a job title like designer, but front-end web developer is a niche within a niche already.

Jina Anne is a front-end developer and designer I admire. Yet, in a panel discussion I was on with her a few years ago, she admits she doesn't think of herself with that title:

When I was at Apple, my job title when I first started out there was front-end developer. Would I call myself that now? No, because it's become such a different thing. Like, I learned HTML/CSS, I never learned JavaScript but I knew enough to work around it. Now—we're talking about job titles—when I hear "front-end developer," I'm going to assume you know a lot more than me.

It seems like, at the time, that lack of a JavaScript focus made Jina feel like she's less skilled than someone who has the official title of front-end developer. I think people would be lucky to have the skills that Jina has in her left pinky finger, but hey that's me. Speaking to Jina recently, she says she still avoids the title specifically because it leads to incorrect assumptions about her skill set.

Mandy Michael put a point on this better than anyone in her article, "Is there any value in people who cannot write JavaScript?":

What I don’t understand is why it’s okay if you can “just write JS”, but somehow you’re not good enough if you “just write HTML and CSS”.

When every new website on the internet has perfect, semantic, accessible HTML and exceptionally executed, accessible CSS that works on every device and browser, then you can tell me that these languages are not valuable on their own. Until then we need to stop devaluing CSS and HTML.

Mandy uses her post for peacemaking. She's telling us, yes, there is a divide, but no, neither side is any more valuable than the other.

Another source of frustration is when the great divide leads to poor craftsmanship. This is what I see as the cause of most of the jeering and poking that occurs across aisles. Brad Frost points to the term "full-stack developer" as a little misleading:

In my experience, “full-stack developers” always translates to “programmers who can do front-end code because they have to and it’s ‘easy’.” It’s never the other way around. The term “full-stack developer” implies that a developer is equally adept at both frontend code and backend code, but I’ve never in my personal experience witnessed anyone who truly fits that description.

Heydon Pickering says something similar. When you're hired at this mythical high level, something like HTML is unlikely to be a strong suit.

... one of the most glaring issues with making Full Stack Developers the gatekeepers of all-things-code is the pitiful quality of the HTML output. Most come from a computer science background, and document structure is simply not taught alongside control structure. It’s not their competency, but we still make it their job.

Just like it may not be my job to configure our deployment pipeline and handle our database scaling (I'd do a terrible job if that task fell to me), perhaps it's best to leave the job of HTML and CSS to do those who do it well. Maybe it's easier to say: Even if there is a divide, that doesn't absolve any of us from doing a good job.

Just as architecture and developer ergonomics are all our jobs, we should view performance, accessibility, and user experience among our line of work. If we can't do a good job with any particular part of it, make sure there's someone else who can do that part. Nobody is allowed to do a bad job.

It's worth mentioning that there are plenty of developers with skill sets that cross the divide and do so gracefully. I think of our own Sarah Drasner who is known as an incredible animator, SVG expert, and a core team member of Vue who also works at Microsoft on Azure. Full stack, indeed.

I expand upon a lot of these topics in another recent conference talk I gave at WordCamp US:

Is there any solution to these problems of suffering craftsmanship and skill devaluation? Are the problems systemic and deeply rooted, or are they surface level and without severe consequence? Is the divide real, or a temporary rift? Is the friction settling down or heating up? Will the front-end developer skill set widen or narrow as the years pass? Let's keep talking about this!

Even as JavaScript continues heating up, Rachel Andrew tells me it used to be hard to fill a CSS workshop, but these days conference organizers are asking for them as they are in hot demand. One thing is certain, like ol' Heraclitus likes to say, the only constant is change.

✌️

The post The Great Divide appeared first on CSS-Tricks.

New CodePen Feature: Prefill Embeds

Css Tricks - Mon, 01/21/2019 - 6:11am

I'm very excited this feature is ready for y'all. You can take any <pre> block of HTML, CSS, and JavaScript (or any combination of them) and enhance it into an embed, meaning you can see the rendered output. Very progressive enhancement friendly! It also lets you pass in stuff like external resources, making it a great choice for, say, documentation sites or the like.

Here's an example right here:

<div id="root"></div> @import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700"); body { margin: 0; font-family: Montserrat, sans-serif; } header { background: #7B1FA2; color: white; padding: 2rem; font-weight: bold; font-size: 125% } class NavBar extends React.Component { render() { return( <header> Hello World, {this.props.name}! </header> ); } } ReactDOM.render( <NavBar name="Chris" />, document.getElementById('root') );

What you can't see is is this block, appended to the embed snippet:

<pre data-lang="html"><div id="root"></div></pre> <pre data-lang="scss" >@import url("https://fonts.googleapis.com/css?family=Montserrat:400,400i,700"); body { margin: 0; font-family: Montserrat, sans-serif; } header { background: #7B1FA2; color: white; padding: 2rem; font-weight: bold; font-size: 125% }</pre> <pre data-lang="babel">class NavBar extends React.Component { render() { return( <header> Hello World, {this.props.name}! </header> ); } } ReactDOM.render( <NavBar name="Chris" />, document.getElementById('root') );</pre>

If I want to update that demo, I can do it by editing this blog post. No need to head back to CodePen. &#x1f64c;

Direct Link to ArticlePermalink

The post New CodePen Feature: Prefill Embeds appeared first on CSS-Tricks.

Firefox DevTools WebConsole 2018 retrospective

Css Tricks - Mon, 01/21/2019 - 6:11am

Here’s a wonderful post by Nicolas Chevobbe on what the Firefox DevTools team was up to last year. What strikes me is how many improvements they shipped — from big visual design improvements to tiny usability fixes that help us make sure our code works as we expect it to in the console.

There are lots of interesting hints here about the future of Firefox DevTools, too. For example, tighter integrations with MDN and, as Nicolas mentions in that post, tools to make it feel like a playground where you can improve your design, rather just fixing things. Anyway, I already feel that Firefox DevTools has the best features for typography of any browser (make sure to check out the “Fonts” tab in the Inspector). I can’t wait to see what happens next!

Direct Link to ArticlePermalink

The post Firefox DevTools WebConsole 2018 retrospective appeared first on CSS-Tricks.

STAR Apps: A New Generation of Front-End Tooling for Development Workflows

Css Tricks - Fri, 01/18/2019 - 7:41am

Product teams from AirBnb and New York Times to Shopify and Artsy (among many others) are converging on a new set of best practices and technologies for building the web apps that their businesses depend on. This trend reflects core principles and solve underlying problems that we may share, so it is worth digging deeper.

Some of that includes:

Naming things is hard, and our industry has struggled to name this new generation of tooling for web apps. The inimitable Orta Theroux calls it an Omakase; I slimmed it down and opted for a simpler backronym pulled from letters in the tooling outlined above: STAR (Design Systems, TypeScript, Apollo, and React).

STAR apps are not "yet another front-end stack." They involve additional opinions and constraints. As such, STAR apps aren’t necessarily easy, either. They have a learning curve. A solo developer may find STAR apps unnecessarily verbose because they front-load communication overhead. STAR apps are more about product team workflow than they are about any specific technology.

However, we find that companies upon companies are finding this stack to be a worthwhile investment. We should ask why.

Context: From LAMP to MEAN

The LAMP stack was identified in 1998 by Michael Kunze to describe the combination of Linux, Apache, MySQL, and PHP as predominant open source technologies to write a full web server. In this model, all rendering and logic was done on the server side, and the role of JavaScript was extremely limited. To this day, this is the most common website architecture due to the popularity of long established frameworks like WordPress, which powers 30% of the Internet.

In the ensuing 20 years, the growth of the web platform (JavaScript in particular), led to a evolution of the "front end" discipline, as a complement to "back end" server-side concerns. Through a combination of Atwood’s Law and Metcalfe’s predictions on the triumph of the web over native platforms, these efforts culminated in a re-imagining of the monolithic architecture to straddle both front and back ends. One prominent encapsulation of this was the MEAN stack, coined by Val Karpov in 2013, to offer "full-stack" JavaScript alternatives, including MongoDB (for NoSQL data storage), Express and Node (to write web servers), and Angular (for writing reactive user interfaces).

What’s changed

However, in the last five years, multiple trends have chipped away at the MEAN stack and the ideal of the full-stack JavaScript monolith:

  • Instead of every developer writing bespoke endpoints, APIs have become an economy of their own with companies like Stripe, Twilio and Zapier growing purely through the strength of their APIs.
  • The acquisition of Firebase and launch of AWS Lambda in 2014 — and the subsequent serverless revolution — has made the concept of doing your own undifferentiated server management and reliability engineering far less appealing.
  • As for proprietary backends, it was clear that not all backend environments were going to be written in JavaScript, particularly with the continuing strength other language frameworks, including Rails, Laravel and .NET, and emerging languages like Go. Even the creators of Express.js and Node.js wound up abandoning JavaScript development altogether.

This has meant that the product engineer’s stack and primary work has shifted even more toward the front end over what was envisioned by the MEAN stack. Chris has described this as a phenomenon that gives extraordinary powers to front-end developers because of the trend toward front-end tooling for what's traditionally been considered back-end territory. Front-end engineering has also evolved, mostly by incrementally adding a constraint layer on top of what we already use — adding a design philosophy, types, schemas, and component structure to how we make our apps.

Why all this change? Stop changing things!

The truth is that we now live in a world where product and business needs now have requirements to bring web app (including mobile web) engineering on par with Android, iOS, and desktop native app development, while our disparate web development tools are still woefully inadequate in comparison to those tightly scoped ecosystems. It’s not that there’s anything inherently wrong with older toolsets or that the new ones are perfect. Instead, the changes can be seen as responses to the underlying needs of product teams:

  • Stronger types: Type-checking isn’t a panacea, nor does it replace the need for tests, but it does enable better tooling and increase code confidence. TypeScript and GraphQL do this for clients and APIs, as Chris Toomey of thoughtbot has shown. Lauren Tan of Netflix has taken this idea even further to propose a full end-to-end Strongly Typed Graph.
  • Integrated designer/developer workflows: A reliance on manual code tests and design reviews doesn’t scale. Design systems now are comprehensive documentation on the how and why of reusable components across an organization. Brad Frost has shown how to set up "workshop" and "storefront" environments for a style guide and design system workflow using Gatsby. Design tools, like Sketch and Framer, have even begun to tightly integrate React and design into streamlined workflows. TypeScript and GraphQL both also offer tightly coupled self-documenting features with TSDoc, GraphiQL, and related IDE integrations.
  • Optimized for change: As product teams embrace iterative agile sprints and split testing, it is increasingly important to use flexible paradigms that embrace incremental adjustments. Dan Abramov of the React team calls this "second order" API design — robustness to changing requirements. Design Systems and React make it easy to compose reusable components at breakneck pace, with TypeScript dramatically shortening feedback loops. Adam Neary of Airbnb shows a wonderful example of refactoring and iterating with React and Apollo GraphQL in production.

Note that "product teams" in this article primarily refer to product engineering teams, though it is often the case that product design and product management are co-located or have heavy, frequent input. Engineering workflows must explicitly take them into account as a result.

Remaining frontiers

Believe it or not, I am being descriptive, rather than prescriptive; I’m not recommending that everybody throw out their code and start writing STAR apps. Rather, I am observing and calling out what I see as a trend where great product teams are all converging on this new pattern. And they just may be on to something.

However, I don’t believe the evolution has reached its conclusion. There are still too many important aspects of modern web app development that need broader consensus, which has resulted in a hodgepodge of custom or one-off solutions and checklists. A big one is performance. The average amount of JavaScript shipped on desktop and mobile has doubled in the last five years. All the wonderful web app engineering in the world will be for nothing if the user navigates away before it loads. The traditional solution has been (often hand-rolled) server-side rendering that's later managed by frameworks like Next.js and After.js. However, this does still require running and managing a server, so static rendering solutions like Gatsby and React-Static have become popular to render apps straight to static markup to be lazily rehydrated later (the last piece of the JAMstack). Progressive Web App technology and patterns help make subsequent loads even faster and serve as a viable alternative to native experiences.

To be continued...

As this story continues to unfold, I believe that a lot more exploration and experimentation needs to happen to smooth the learning curve for more teams to adopt STAR app workflows. In fact, I am learning about it myself in the open at STAR Labs and invite you to tag along. If you have experiences to share or questions to ask, I am all ears.

The post STAR Apps: A New Generation of Front-End Tooling for Development Workflows appeared first on CSS-Tricks.

Intro to React Hooks

Css Tricks - Fri, 01/18/2019 - 5:15am

Hooks make it possible to organize logic in components, making them tiny and reusable without writing a class. In a sense, they’re React’s way of leaning into functions because, before them, we’d have to write them in a component and, while components have proven to be powerful and functional in and of themselves, they have to render something on the front end. That’s all fine and dandy to some extent, but the result is a DOM that is littered with divs that make it gnarly to dig through through DevTools and debug.

Well, React Hooks change that. Instead of relying on the top-down flow of components or abstracting components in various ways, like higher-order components, we can call and manage flow inside of a component. Dan Abramov explains it well in his Making Sense of React post:

Hooks apply the React philosophy (explicit data flow and composition) inside a component, rather than just between the components. That’s why I feel that Hooks are a natural fit for the React component model.

Unlike patterns like render props or higher-order components, Hooks don’t introduce unnecessary nesting into your component tree. They also don’t suffer from the drawbacks of mixins.

The rest of Dan’s post provides a lot of useful context for why the React team is moving in this direction (they're now available in React v16.7.0-alpha) and the various problems that hooks are designed to solve. The React docs have an introduction to hooks that, in turn, contains a section on what motivated the team to make them. We’re more concerned with how the heck to use them, so let’s move on to some examples!

The important thing to note as we get started is that there are nine hooks currently available, but we're going to look at what the React docs call the three basic ones: useState(), useEffect, and setContext(). We’ll dig into each one in this post with a summary of the advanced hooks at the end.

Defining state with useState()

If you’ve worked with React at any level, then you’re probably familiar with how state is generally defined: write a class and use this.state to initialize a class:

class SomeComponent extends React.component { constructor(props) super(props); this.state = { name: Barney Stinson // Some property with the default state value } }

React hooks allow us to scrap all that class stuff and put the useState() hook to use instead. Something like this:

import { useState } from 'react'; function SomeComponent() { const [name, setName] = useState('Barney Stinson'); // Defines state variable (name) and call (setName) -- both of which can be named anything }

Say what?! That’s it! Notice that we’re working outside of a class. Hooks don’t work inside of a class because they’re used in place of them. We’re using the hook directly in the component:

import { useState } from 'react'; function SomeComponent() { const [name, setName] = useState('Barney Stinson'); return <div> <p>Howdy, {name}</p> </div> }

Oh, you want to update the state of name? Let’s add an input and submit button to the output and call setName to update the default name on submission.

import { useState } from 'react' function SomeComponent() { const [input, setValue] = useState(""); const [name, setName] = useState('Barney Stinson'); handleInput = (event) => { setValue(event.target.value); } updateName = (event) => { event.preventDefault(); setName(input); setValue(""); } return ( <div> <p>Hello, {name}!</p> <div> <input type="text" value={input} onChange={handleInput} /> <button onClick={updateName}>Save</button> </div> </div> ) }

See the Pen React Hook: setState Example by Geoff Graham (@geoffgraham) on CodePen.

Notice something else in this example? We’re constructing two different states (input and name). That’s because the useState() hook allows managing multiple states in the same component! In this case, input is the property and setValue holds the state of the input element, which is called by the handleInput function then triggers the updateName function that takes the input value and sets it as the new name state.

Create side effects with useEffect()

So, defining and setting states is all fine and dandy, but there’s another hook called useEffect() that can be used to—you guessed it—define and reuse effects directly in a component without the need for a class or the need to use both redundant code for each lifecycle of a method (i.e. componentDidMount, componentDidUpdate, and componentWillUnmount).

When we talk about effects, we’re referring to things like API calls, updates to the DOM, and event listeners, among other things. The React documentation cites examples like data fetching, setting up subscriptions, and changing the DOM as possible use cases for this hook. Perhaps the biggest differentiator from setState() is that useEffect() runs after render. Think of it like giving React an instruction to hold onto the function that passes and then make adjustments to the DOM after the render has happened plus any updates after that. Again, the React documentation spells it out nicely:

By default, it runs both after the first render and after every update. [...] Instead of thinking in terms of “mounting" and “updating", you might find it easier to think that effects happen “after render". React guarantees the DOM has been updated by the time it runs the effects.

Right on, so how do we run these effects? Well, we start off by importing the hook the way we did for setState().

import { useEffect } from 'react';

In fact, we can call both setState() and useEffect() in the same import:

import { useState, useEffect } from 'react';

Or, construct them:

const { useState, useEffect } = React;

So, let’s deviate from our previous name example by hooking into an external API that contains user data using axios inside the useEffect() hook then renders that data into a list of of users.

First, let’s bring in our hooks and initialize the App.

const { useState, useEffect } = React const App = () => { // Hooks and render UI }

Now, let’s put setState() to define users as a variable that contains a state of setUsers that we’ll pass the user data to once it has been fetched so that it’s ready for render.

const { useState, useEffect } = React const App = () => { const [users, setUsers] = useState([]); // Our effects come next }

Here’s where useEffect() comes into play. We’re going to use it to connect to an API and fetch data from it, then map that data to variables we can call on render.

const { useState, useEffect } = React const App = () => { const [users, setUsers] = useState([]); useEffect(() => { // Connect to the Random User API using axios axios("https://randomuser.me/api/?results=10") // Once we get a response, fetch name, username, email and image data // and map them to defined variables we can use later. .then(response => response.data.results.map(user => ({ name: `{user.name.first} ${user.name.last}`, username: `{user.login.username}`, email: `{user.email}`, image: `{user.picture.thumbnail}` })) ) // Finally, update the `setUsers` state with the fetched data // so it stores it for use on render .then(data => { setUsers(data); }); }, []); // The UI to render }

OK, now let’s render our component!

const { useState, useEffect } = React const App = () => { const [users, setUsers] = useState([]); useEffect(() => { axios("https://randomuser.me/api/?results=10") .then(response => response.data.results.map(user => ({ name: `{user.name.first} ${user.name.last}`, username: `{user.login.username}`, email: `{user.email}`, image: `{user.picture.thumbnail}` })) ) .then(data => { setUsers(data); }); }, []); return ( <div className="users"> {users.map(user => ( <div key={user.username} className="users__user"> <img src={user.image} className="users__avatar" /> <div className="users__meta"> <h1>{user.name}</h1> <p>{user.email}</p> </div> </div> ))} </div> ) }

Here’s what that gets us:

See the Pen React Hook: setEffect example by Geoff Graham (@geoffgraham) on CodePen.

It’s worth noting that useEffect() is capable of so, so, so much more, like chaining effects and triggering them on condition. Plus, there are cases where we need to cleanup after an effect has run—like subscribing to an external resource—to prevent memory leaks. Totally worth running through the detailed explanation of effects with cleanup in the React documentation.

Context and useContext()

Context in React makes it possible to pass props down from a parent component to a child component. This saves you from the hassle of prop drilling. However, you could only make use of context in class components, but now you can make use of context in functional components using useContext() . Let’s create a counter example, we will pass the state and functions which will be used to increase or decrease the count from the parent component to child component using useContext(). First, let’s create our context:

const CountContext = React.createContext();

We’ll declare the count state and increase/decrease methods of our counter in our App component and set up the wrapper that will hold the component. We’ll put the context hook to use in the actual counter component in just a bit.

const App = () => { // Use `setState()` to define a count variable and its state const [count, setCount] = useState(0); // Construct a method that increases the current `setCount` variable state by 1 with each click const increase = () => { setCount(count + 1); }; // Construct a method that decreases the current `setCount` variable state by 1 with each click. const decrease = () => { setCount(count - 1); }; // Create a wrapper for the counter component that contains the provider that will supply the context value. return ( <div> <CountContext.Provider // The value is takes the count value and updates when either the increase or decrease methods are triggered. value={{ count, increase, decrease }} > // Call the Counter component we will create next <Counter /> </CountContext.Provider> </div> ); };

Alright, onto the Counter component! useContext() accepts an object (we’re passing in the CountContext provider) and allows us to tell React exactly what value we want (`count) and what methods trigger updated values (increase and decrease). Then, of course, we’ll round things out by rendering the component, which is called by the App.

const Counter = () => { const { count, increase, decrease } = useContext(CountContext); return ( <div className="counter"> <button onClick={decrease}>-</button> <span className="count">{count}</span> <button onClick={increase}>+</button> </div> ); };

And voilà! Behold our mighty counter with the count powered by context objects and values.

See the Pen React hooks - useContext by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Wrapping up

We’ve merely scratched the surface of what React hooks are capable of doing, but hopefully this gives you a solid foundation. For example, there are even more advanced hooks that are available in addition to the basic ones we covered in this post. Here’s a list of those hooks with the descriptions offered by the documentation so you can level up now that you’re equipped with the basics:

Hook Description userReducer() An alternative to useState. Accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method. useCallback() Returns a memoized callback. Pass an inline callback and an array of inputs. useCallback will return a memoized version of the callback that only changes if one of the inputs has changed. useMemo() Returns a memoized value. Pass a “create" function and an array of inputs. useMemo will only recompute the memoized value when one of the inputs has changed. useRef() useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component. useImperativeMethods useImperativeMethods customizes the instance value that is exposed to parent components when using ref. As always, imperative code using refs should be avoided in most cases. useImperativeMethods should be used with forwardRef. useLayoutEffect The signature is identical to useEffect, but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.

The post Intro to React Hooks appeared first on CSS-Tricks.

Does it mutate?

Css Tricks - Fri, 01/18/2019 - 5:13am

This little site by Remy Sharp's makes it clear whether or not a JavaScript method changes the original array (aka mutates) or not.

I was actually bitten by this the other day. I needed the last element from an array, so I remembered .pop() and used it.

const arr = ["doe", "ray", "mee"]; const last = arr.pop(); // mee, but array is now ["doe", "ray"]

This certainly worked great right away, but I didn't realize the original array had changed and it caused a problem. Instead, I had to find the non-mutating alternative:

const arr = ["doe", "ray", "mee"]; const last = arr.slice(-1); // ["mee"], arr is unchanged

Related: Array Explorer

Direct Link to ArticlePermalink

The post Does it mutate? appeared first on CSS-Tricks.

Angular, Autoprefixer, IE11, and CSS Grid Walk into a Bar…

Css Tricks - Fri, 01/18/2019 - 5:13am

I am attracted to the idea that you shouldn't care how the code you author ends up in the browser. It's already minified. It's already gzipped. It's already transmogrified (real word!) by things that polyfill it, things that convert it into code that older browsers understand, things that make it run faster, things that strip away unused bits, and things that break it into chunks by technology far above my head.

The trend is that the code we author is farther and farther away from the code we write, and like I said, I'm attracted to that idea because generally, the purpose of that is to make websites faster for users.

But as Dave notes, when something goes wrong...

As toolchains grow and become more complex, unless you are expertly familiar with them, it’s very unclear what transformations are happening in our code. Tracking the differences between the input and output and the processes that code underwent can be overwhelming. When there’s a problem, it’s increasingly difficult to hop into the assembly line and diagnose the issue and often there’s not an precise fix.

Direct Link to ArticlePermalink

The post Angular, Autoprefixer, IE11, and CSS Grid Walk into a Bar… appeared first on CSS-Tricks.

2019 CSS Wishlist

Css Tricks - Thu, 01/17/2019 - 12:02pm

What do you wish CSS could do natively that it can't do now? First, let's review the last time we did this in 2013.

  1. ❌ "I'd like to be able to select an element based on if it contains another particular selector"
  2. ❌ "I'd like to be able to select an element based on the content it contains"
  3. ❌ "I'd like multiple pseudo elements"
  4. ❌ "I'd like to be able to animate/transition something to height: auto;"
  5. ❌ "I'd like things from Sass, like @extend, @mixin, and nesting"
  6. ❌ "I'd like ::nth-letter, ::nth-word, etc"
  7. ✅ "I'd like all the major browsers to auto-update"

Ouch. Oh well. I'm not sure how hotly requested all those actually are or how feasible it is to even implement them. They're merely ideas that I thought we be useful in 2013, and as it turns out, I still do.

This time, instead of me making my own list, let's have a gander around the internet at other people who have rounded up CSS desires.

TL;DR List

In observing several sources of conversation around things people desire in CSS, these seem like the most common asks:

  • Parent queries. As in, selecting an element any-which-way, then selecting the parent of that element. We have some proof it's possible with :focus-within.
  • Container queries. Select a particular element when the element itself is under certain conditions.
  • Standardized styling of form elements.
  • Has/Contains Selectors.
  • Transitions to auto dimensions.
  • Fixed up handling of viewport units.

Notably, what's interesting to me is the lack of people asking for style scoping. It came up a little, but not a ton. It seems like such a big part of the CSS-in-JS conversation, so I'm surprised to see so little mention of it in the context of general "what does CSS need?" conversations.

Jen Simmons asked what's on our lists

Making a wish list of all the things I’d love to see happen in the world of CSS in 2019. What’s on your list? Things you want to learn? Problems you want help solving? New properties you need? Design ideas you wish you could code? Resources you’d love to have? Name your desire.

— Jen Simmons (@jensimmons) November 14, 2018

Notable replies from the thread:

  • Aspect ratios (it's weirdly tricky in CSS, coming to HTML probably, and maybe we'll get it natively in CSS with a property someday)
  • Exclusions
  • Regions
  • Subgrid (it's coming!)
  • text-wrap: avoid-widows-and-orphans
  • Nesting
  • Outline with radius
  • Animated background gradients (without faking it by moving them or whatever else)
  • text-overflow:ellipsis over multiple lines / line clamping
  • 0-to-auto transitions
  • Parent selectors
  • Async @import
  • Math functions like sqrt(), sin() and cos()
  • font-min-size and font-max-size
  • Masonry
Tab Atkins wanted to know what parts of CSS give us the most trouble

What parts of CSS give you the most trouble due to browser behavior differences? Collecting some data, please RT. (If answer is different for mobile vs desktop, let me know.)

— &#x1f496;Taudry Hepburn&#x1f496; (@tabatkins) October 3, 2018

Notable replies from the thread:

  • Tons and tons of requests for a standardized way to style form elements — not just for styling desire, but for accessibility to prevent trading standards for styling.
  • Being able to test browser support of more than just property/values with @supports
  • Improved handling of viewport units and their relationship to other browser UI
  • Improved handling of multi-column layout handling
  • Elastic scrolling
Tommy Hodgins did a CSS+JS advent calendar on Twitter that documents interesting possibilities

Dec 1: Parent Selector &#x1f384;&#x1f381; Though CSS doesn't have a :parent selector, you can create your own with a small JavaScript function and use a selector like [--parent] in your CSS stylesheets today!

demo: https://t.co/9N1A1Un8XT
code: https://t.co/NNUuvOi1zH#css #javascript pic.twitter.com/Nv8V3rl2AF

— Tommy Hodgins (@innovati) December 1, 2018

Tommy's list:

  • Parent selector
  • Has selector
  • Closest selector
  • First in document (like how querySelector works)
  • Elder sibling selector
  • Previous sibling selector
  • Contains selector
  • Regex selector
  • Computed style selector
  • :nth-letter / :nth-word
  • Media pseudo selectors
  • Not-blank valid/invalid selector
  • Element queries
  • Attribute comparison selectors
  • Custom specificity
  • Visibility selectors
  • Overflow detection selector
  • User agent detection selector
  • Storage queries
  • Date queries
  • Protocol queries
  • Deep hover
We asked as well

Putting together a list of most-wanted native CSS features. There are lots of ideas out there!

Hit me with quick hit ideas. Don't think too hard.

— CSS-Tricks (@css) December 17, 2018

Notable replies from the thread:

  • Container queries
  • Has selector
  • Regions
  • Color modification functions
  • Nesting
  • Shaders
  • Transition to auto dimensions / transition from display: none;
  • Previous sibling selector
  • font-size: fit;
  • Styling grid-template-areas
  • Animation between grid-template-areas
  • Types for custom properties
  • clip-path accepting paths
  • inline-styles: ignore;
  • Aspect ratios
  • Scoping
  • // single line comments
  • Corner shapes

The post 2019 CSS Wishlist appeared first on CSS-Tricks.

Create Smart WordPress Forms in Less Than 5 Minutes with WPForms

Css Tricks - Thu, 01/17/2019 - 12:00pm

(This is a sponsored post.)

Most online form solutions are either too complex or too expensive.

We believe you shouldn't have to spend hours creating online forms for your business. That's why we built WPForms, a drag and drop WordPress form builder that's both EASY and POWERFUL.

WPForms allows you to create beautiful contact forms, email subscription forms, payment forms, smart survey forms, and basically every other type of form for your website within minutes!

Since launching in 2016, WPForms has taken the market by surprise with it's pre-built templates and smart workflows. Currently, WPForms is being used on over 1 million WordPress websites.

WPForms also maintains a 4.9 out of 5 star rating average on WordPress.org with over 3,000 five-star ratings.

WPForms Features

Here are the features that makes WPForms the most powerful and user-friendly WordPress form plugin in the market.

  • Drag & Drop Form Builder - create smart forms in minutes without writing any code.
    150+ Pre-Made Form Templates - start with our form templates to save time, and customize them as needed.
    Smart Conditional Logic - customize your forms based on user interaction to collect the most relevant information.
  • Entry Management - See all your leads right inside your WordPress dashboard with Geo-location data, and other powerful features.
  • Instant Form Notifications - Get email notifications when a user submits a form. You can smart routing to send the inquiry to the right person in your team.
  • Spam Protection - Our smart captcha and honeypot automatically prevents all spam submissions. You can also add custom CAPTCHA questions as well.
  • Email Marketing Integrations - Integrate with your email marketing service using our native integration for MailChimp, AWeber, Constant Contact, Drip, and countless others. You can use also use our Zapier integration to connect your forms to over 1000+ other apps.
  • Payment Forms - Create online payments using Stripe or PayPal. Recurring payment support is built-in as well.
  • Surveys & Polls - Easily create smart survey forms and analyze your data with our interactive reports. Our WordPress survey plugin is by far the best solution in the industry.
  • Form Abandonment - Unlock more leads by capturing partial form submissions.
  • Form Permissions - Lock your forms and manage access control with password, logged-in users, and other restrictions.
  • Signature - Allow users to sign your online forms with their mouse or touch screen.
  • Post Submission - Allow users to submit guest blog posts and other content directly to your WordPress site without logging into the dashboard. Great for user-submitted content.
  • User Registration - Create custom user registration and login forms for WordPress with just a few clicks. Also include advanced features like profile field mapping, spam registration protection, etc.
  • All Advanced Fields You Need - From radio button to file uploads to multi-page forms to Likert scale, we have all the fields you need.
  • Easy to Customize - Completely customize your WordPress forms with section dividers, HTML blocks, and custom CSS. WPForms also comes with hooks and filters for developers to extend and create custom functionality.

Smart business owners, designers, and developers love WPForms, and you will too!

Unlike other form solutions that charge a monthly subscription which increases as your business grows, WPForms allows you to create unlimited forms and get unlimited entries for a small yearly fee.

Get Started with WPForms Pro Today

Bonus: CSS Tricks users can get 50% off by using the coupon: SAVE50

Need more social proof? Read WPForms user reviews to see why over 1 million websites choose WPForms to build powerful WordPress forms.

If you're just starting out and don't need all the advanced features, then you can try our free WPForms Lite plugin for creating a simple contact form. You can simply download it from your WordPress site by searching for WPForms in the plugin search of your WordPress site.

Direct Link to ArticlePermalink

The post Create Smart WordPress Forms in Less Than 5 Minutes with WPForms appeared first on CSS-Tricks.

How I Built a GPS-Powered Weather Clock With My Old iPhone 4

Css Tricks - Thu, 01/17/2019 - 5:03am

My first smartphone was an iPhone 4s. I remember the excitement of exploring its capabilities at a time when it was the coolest thing around. Eventually, of course, I replaced it with a newer model and the old iPhone, still in mint condition, gathered dust for two years. What a waste!

But was it? It occurred to me that I could repurpose the old iPhone to create a useful weather clock for our hallway.

Who needs Nest anyway?

In the process, I discovered that reusing an old device is not only fun and economical, it can also deepen your understanding of web standards. In this tutorial, I will show how I created a small web page to display the date, time, and current weather conditions based on the current GPS location. Together, we’ll retrieve weather data from a public API and hide an API key in a PHP file for security. Finally, we’ll look at adding a manifest file and meta tags so that users can save the page to a device’s home screen and then launch it as a standalone app, including a custom icon for it.

Here is a screen shot of what we’re aiming for:

Step 1: What time is it?

See the Pen Wall Clock by Steven Estrella (@sgestrella) on CodePen.

The HTML for the clock has some placeholder text that we will eventually replace. All we really need at this moment is a centered <main> container element and a couple of semantic <time> elements for the date and time. The <span> tag within the second <time> element will be styled specially to display the running seconds and the meridian. The datetime attribute within the <time> elements will be updated dynamically with JavaScript.

<main id="container" class="daymode"> <time id="date" datetime="" class="clocktext">Someday, Anymonth 15, 20XX</time> <time id="time" datetime="" class="clocktext">12:00<span>:00 PM</span></time> </main>

A little responsive design is key here. We want this to fit nicely on an iPhone 4s screen or any other small-ish smartphone in both portrait and landscape modes. We also want it to work well on a desktop web browser, of course. We can’t use any bleeding-edge CSS or JavaScript, however, because older devices like my iPhone 4s won’t understand it.

I wound up taking things up a notch by creating styles specific for the time of day and we’ll definitely get to that as well. We could even leverage a media query to darken the daytime style for Mac users who have dark mode turned on in the latest MacOS.

The <span> tag with the running seconds and meridian will wrap nicely based on a width of 2em which is just large enough to accommodate two capital letters (i.e. AM and PM). The final CSS that’s needed is a media query to bump up font sizes when the clock is in landscape mode, or really any device with a viewport wider than 480px.

Here are the base styles we’re looking at, with the more decorative styles in the final app removed for brevity:

/* Base nighttime styles */ .nightmode { background-color: #121212; color: #fff; } /* Base daytime styles */ .daymode { background-color: #87ceeb; color: #333; } /* Target MacOS users who have Dark Mode enabled */ @media (prefers-color-scheme: dark) { .daymode { background-color: #003; color: #ffc; } } /* Used to wrap any lines of text */ .clocktext { display: block; margin: 0; padding: 1px 0 0 0; text-align: center; white-space: nowrap; width: 100%; } #date { font-size: 1.3rem; padding-top: 15px; } #time { font-size: 5rem; margin: 1px 0 0 0; } #time span { display: inline-block; font-size: 1.5rem; line-height: 1.5; margin: 0 0 0 0.5em; padding: 0; text-align: left; vertical-align: baseline; white-space: normal; width: 2em; } @media (min-width: 480px){ #date {font-size: 2rem;} #time {font-size: 8rem;} #time span { font-size: 2rem; line-height: 2; } }

For the JavaScript, I chose ES5 because many features of ES6 don’t work on the mobile Safari browser in iOS 9.35, which is the final iOS that runs on the iPhone 4s. Fortunately, ES5 is more than up to the task and the app runs properly on newer devices as well.

We need variables for the current date and time (now), the element that will display the date (dd), the element that will display the time (td) and the names of the months and days. Once the page is loaded, an init function is called to update the time every second (1000 milliseconds). The getClockStrings() function updates the value in the now Date object and returns an object containing HTML strings for the date and time. Then the updateTime() function updates the HTML to show the time. One lesser-used feature here is the inclusion of the toISOString() method of the Date object which adds a machine-readable date string to the datetime attribute of the two <time> elements.

Here’s what that boils dow to, using the JavaScript from the demo:

// NOTE: ES5 chosen instead of ES6 for compatibility with older mobile devices var now, dd, td; var months = ["January","February","March","April","May","June","July","August","September","October","November","December"]; var days = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]; document.addEventListener("DOMContentLoaded", init, false); function init() { dd = document.getElementById("date"); td = document.getElementById("time"); updateTime(); setInterval(updateTime,1000); } function updateTime() { var clockdata = getClockStrings(); dd.innerHTML = clockdata.datehtml; td.innerHTML = clockdata.timehtml; dd.dateTime = now.toISOString(); td.dateTime = now.toISOString(); } function getClockStrings() { now = new Date(); var year = now.getFullYear(); var month = months[now.getMonth()]; var date = now.getDate(); var day = days[now.getDay()]; var hour = now.getHours(); var minutes = now.getMinutes(); var seconds = now.getSeconds(); var meridian = hour < 12 ? "AM" : "PM"; var clockhour = hour > 12 ? hour - 12 : hour; if (hour === 0) {clockhour = 12;} var clockminutes = minutes < 10 ? "0" + minutes : minutes; var clockseconds = seconds < 10 ? "0" + seconds : seconds; var datehtml = day + ", " + month + " " + date + ", " + year; var timehtml = clockhour + ":" + clockminutes + "<span>:" + clockseconds + " " + meridian + "</span>"; return {"datehtml":datehtml,"timehtml":timehtml}; } Step 2: Where are you?

See the Pen Clock with GPS by Steven Estrella (@sgestrella) on CodePen.

The Geolocation API is an easy way to get the user’s accurate location. We can do that when the page loads, but good manners and Chrome’s best practices audit dictate that we ask the user to initiate the location feature. So, we must add a button and a <div> to the HTML to display the GPS information we receive.

<button id="gpsbutton">Get GPS Location</button> <div id="gps" class="clocktext infotext"></div>

These new items require their own styles — mine can be seen in the embedded Pen above. The important thing is to add the class selector rule for the infotext class as well as the two ID selector rules for the gpsbutton.

Finally, we’ll need to add the modified infotext class selector rule within the media query.

Again, the basic styles minus decorative styling for brevity:

/* The geolocation coordinates upon clicking GPS button */ .infotext { font-size: 1.3rem; line-height: 1.4; padding: 0 5px 0 5px; width: auto; } /* The button itself */ #gpsbutton { -webkit-appearance: none; -moz-appearance: none; display: block; margin: 0 auto; width: auto; cursor: pointer; } #gpsbutton:hover { /* Styles for the hover state */ } @media (min-width: 480px){ /* Add the rule below to the end of the media query */ .infotext {font-size: 1.8rem;} }

The JavaScript requires a few new variables for the latitude, longitude, GPS <div>, and GPS <button>. When clicked, the GPS button calls the getLocation() function which tests for the availability of geolocation support in the browser. If it finds such support, it calls the getCurrentPosition method of the navigator.geolocation object and passes a reference to a success callback function named showPosition and an error callback function named geoError.

At this point, the browser will ask the user for permission to obtain their GPS location. If the visitor refuses, an appropriate message is displayed. If the user approves, the showPosition() function then displays the latitude and longitude and hides the GPS button.

Here’s the Javascript we get based on what we’ve covered in this section:

// ... var lat, lon, gd, gpsbutton; // ... function init(){ // ... gd = document.getElementById("gps"); gpsbutton = document.getElementById("gpsbutton"); gpsbutton.addEventListener("click",getLocation,false); // ... } function updateTime(){ // ... var sec = now.getSeconds(); var minutes = now.getMinutes(); if (sec === 0){ if (minutes % 5 === 0){ getLocation(); // Get location every 5 minutes while the app is running } } } function getClockStrings(){ // ... } function getLocation() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(showPosition,geoError); }else{ gd.innerHTML = "location unknown"; } } function geoError(){ gd.innerHTML = "location detection disabled"; } function showPosition(position) { gpsbutton.style.display = "none"; lat = position.coords.latitude; lon = position.coords.longitude; gd.innerHTML = "GPS: " + lat.toFixed(2) + " | " + lon.toFixed(2); } Step 3: How’s the weather?

Adding current weather conditions to this clock is a useful feature. Fortunately, the good folks at OpenWeatherMap.org allow access to basic weather information for free. Sign up for a free account there and you will be given an API key you can use in your web development. The free account provides current conditions and 5-day forecasts for any valid GPS location you throw at it. Just be sure to call the API no more than 60 times per minute or you will be prodded to upgrade to a paid account. Once you have an API key, substitute it for the words YOUR_API_KEY_HERE in this code sample and then paste the code into the browser’s location bar. You will receive a JSON object containing the weather for my location here in Pennsylvania. Experiment with different latitudes and longitudes. You can find coordinates for any major city at LatLong.net where the coordinates are given in the decimal format you need.

http://api.openweathermap.org/data/2.5/weather?lat=40.15&lon=-75.21&APPID=YOUR_API_KEY_HERE

See the Pen Clock and Weather by Steven Estrella (@sgestrella) on CodePen.

Add the HTML

Just below the GPS <button>, add the following to the HTML:

<div id="weather" class="clocktext infotext"></div> <img id="icon" src="https://openweathermap.org/img/w/01n.png" alt="weather icon" /> Add the CSS

The CSS needs styles for the new weather <div> and the icon image. Note that the icon is set to 0 opacity initially. That will be changed in the JavaScript code once valid weather information is retrieved.

#weather { display: block; width: auto; } #icon { display: inline-block; opacity: 0; vertical-align: top; width: 50px; height: 50px; } @media (min-width: 480px){ /* Add the rule below to the end of the media query */ #weather {display: inline-block;} } Add the JavaScript

We need to add variables to reference the weather URL, the weather <div> (wd), and the weather icon. We also need to decide on Fahrenheit or Celsius. The Boolean value for usephp should be set to false for now. We will discuss hiding your API key in a PHP document a little later. The locationRequested Boolean value will help us avoid calling the weather and geolocation APIs before the user has requested them. The sunset and sunrise time variables will allow us to change the appearance of the clock based on the time of day. The iconurl value provides the stem of the URL we need to retrieve weather icons. We also need a random number between 0 and 14 to use in our updateTime function so that all our users don’t request weather at the same minute each quarter hour. If you have your own set of icons, you can change the URL value for iconurl . The file names for the PNG icons are available at OpenWeatherMap.org.

// ... var weatherurl, wd, icon, weatherminute; var temperaturescale = "F"; // Set to F or C (fahrenheit or celsius) var usephp = false; // Set to true to use a PHP document to hide your api key var locationRequested = false; var sunsettime = 0; var sunrisetime = 0; var iconurl = "https://openweathermap.org/img/w/"; // ... function init(){ //... Add these lines before the updateTime call at the end of the function wd = document.getElementById("weather"); icon = document.getElementById("icon"); weatherminute = randRange(0,14); // ... } // Random number utility function function randRange(min, max) { return Math.floor(Math.random()*(max-min+1))+min; }

Next we will modify the final if block of the updateTime() function. We wish to avoid unnecessary calls to the weather and geolocation APIs so it is important to test for sec === 0 to be sure we don't call either API 60 times in a given minute. We also wish to call the APIs only if the user has approved the browser’s geolocation request.

function updateTime(){ //... if (locationRequested && sec === 0){ checkForSunset(); // Checks for sunset once each minute if (minutes % 15 === weatherminute){ getWeather(); // Get weather every 15 minutes while the app is running // weatherminute is a random number between 0 and 14 to ensure // that users don't all hit the API at the same minute } if (minutes % 5 === 0){ getLocation(); // Get location every 5 minutes while the app is running } } }

In the showPosition() function, the URL to request the weather data will be either a relative path to the PHP file or a full HTTPS URL pointing to the OpenWeatherMap.org service. In both cases, we will be passing the latitude and longitude in the query string of the URL. For the APPID, please substitute your own API Key for the words YOUR_API_KEY_HERE unless you are using the PHP solution discussed in Step 4 below.

function showPosition(position) { //... if (usephp){ weatherurl = "clock.php?lat=" + lat + "&lon=" + lon; }else{ weatherurl = "https://api.openweathermap.org/data/2.5/weather?"; weatherurl += "lat=" + lat + "&lon=" + lon + "&APPID="; weatherurl += "YOUR_API_KEY_HERE"; } if (!locationRequested){ getWeather(); locationRequested = true; } }

The showPosition() function then calls getWeather() which updates the weather <div> to let the user know something is happening while the weather data is being retrieved. I opted to use the older XMLHttpRequest standard because fetch is not supported on old devices like the iPhone 4s. If the weather data request is being channeled through a PHP document, the response type will be "document" rather than plain text so we have to test for that. If that is the case, the JSON object we need will be in the textContent property of the body of the response. Otherwise, we only need the plain text found in the responseText property. The data is then parsed as a JSON object and sent to the processWeather() function.

function getWeather() { wd.innerHTML = "getting weather"; var xhttp = new XMLHttpRequest(); xhttp.responseType = usephp ? "document" : "text"; // The PHP file returns a document rather than plain text xhttp.onreadystatechange = function() { if (this.readyState === 4 && this.status === 200) { // When using PHP as a data source we need the `textContent` // of the body of the returned document var data = usephp ? xhttp.response.body.textContent : xhttp.responseText; processWeather(JSON.parse(data)); } }; xhttp.open("GET", weatherurl, true); xhttp.send(); }

The JSON object sent to processWeather() will look something like this:

{"coord":{"lon":-75.21,"lat":40.15}, "weather":[{"id":701,"main":"Mist","description":"mist","icon":"50n"}], "base":"stations", "main":{"temp":276.42,"pressure":1011,"humidity":100,"temp_min":275.15,"temp_max":277.15},"visibility":16093,"wind":{"speed":2.1,"deg":310},"clouds":{"all":90},"dt":1545021480, "sys":{"type":1,"id":4743,"message":0.1513,"country":"US","sunrise":1545049047,"sunset":1545082605},"id":5190089,"name":"Fort Washington","cod":200}

From this JSON data, we need to grab the weather property that contains the description of the current conditions and the filename for the weather icon. The <img> tag in the html that has the ID of "icon" is then updated with a new src property value to load the icon image. The temperature is part of the main property but it has to be converted to Fahrenheit or Celsius (most humans don’t think in Kelvin). When that is done, the current conditions can be assigned to the innerHTML property of the weather <div>. The times for sunrise and sunset are found in the sys property of the data. Once we have those, we can call the checkForSunset() function and modify the style to match the time of day.

function processWeather(data){ var weather = data["weather"][0]; icon.src = iconurl + weather.icon + ".png"; icon.style.opacity = 1; var localtemperature = convertTemperature(data["main"].temp).toFixed(0); var weatherstring = localtemperature + "°" + temperaturescale + "&nbsp;&nbsp;" + weather.description; wd.innerHTML = weatherstring; sunsettime = Number(data["sys"].sunset); sunrisetime = Number(data["sys"].sunrise); checkForSunset(); } function checkForSunset(){ var nowtime = now.getTime()/1000; // Changes the presentation style if the time of day is after sunset // or before the next day's sunrise var isDark = nowtime > sunsettime || nowtime < sunrisetime; document.getElementById("container").className = isDark ? "nightmode":"daymode"; } function convertTemperature(kelvin){ // Converts temps in kelvin to celsius or fahrenheit var celsius = (kelvin - 273.15); return temperaturescale === "F" ? celsius * 1.8 + 32 : celsius; } Step 4: Do I really have to show you my API key?

I used a disposable API key to create a working demo. Generally, however, putting an API key in plain text within the code of a front-end web application seems like a bad idea. Others might copy it and use up your API access quota. If you have access to a typical web server (CodePen doesn’t do PHP), you can hide the API key in a PHP file. Here is some sample code. Substitute the API key and upload the file as clock.php into the same directory as the main HTML file. The PHP file serves as a sort of proxy to the OpenWeatherMap API that we’re using to fetch data in the demo. If it has any problem retrieving weather data, it simply returns an appropriately structured object with "Weather Unavailable" as a description and a temperature that converts to 0° Fahrenheit. The API key is never transferred from the server to the browser so there is nothing for prying eyes to see.

I would be interested to hear from readers if you know of a secure, serverless solution to hiding an API key (Netlify or Docker perhaps?) because it’d be nice not to have to spin up our own server to store and hit the data. Chime in if you have some thoughts.

<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Clock Data</title></head> <body> <?php error_reporting(0); $latitude = "80"; $longitude = "-85"; if (isset($_GET["lat"]) && isset($_GET["lon"])) { $latitude = $_GET["lat"]; $longitude = $_GET["lon"]; } $endpoint = "http://api.openweathermap.org/data/2.5/weather?"; $apikey = "YOUR_API_KEY_HERE"; $weatherurl = $endpoint . "lat=" . $latitude . "&lon=" . $longitude . "&appid=" . $apikey; $jsonfile = file_get_contents($weatherurl); if ($jsonfile !== false){ echo "$jsonfile"; } else { echo '{"weather":[{"description":"Weather Unavailable","icon":"01n"}],"main":{"temp":255.372278}}'; } ?> </body> </html>

If anyone else tries to use this PHP file from another domain, the browser should throw an error like the one in the following example. I loaded a copy of the weather clock on my makepages.com domain and tried to access the PHP file on my shearspiremedia.com domain. These days, the same-origin policy is in place by default on typical commercial web server installations. You might need to confirm that is the case on the server you are using.

[Error] Origin https://makepages.com is not allowed by Access-Control-Allow-Origin. [Error] XMLHttpRequest cannot load https://shearspiremedia.com/demos/clock/clock.php?lat=40.14616446413611&lon=-75.20946717104738 due to access control checks.

Next, update the usephp variable in the JavaScript file and test:

var usephp = true; // Set to true to use a PHP document to hide your api key Step 5: Can I please go full screen?

Once the app is up and working, it can load on any smartphone browser. The iPhone, however, is forced to endure the presence of the location bar and footer. Yuck!

It would be lovely to be able to view it full screen instead. To do that, we need a manifest file to tell the device that we wish to view the clock as a standalone app and to tell Android devices where the app icons are located. Here is my manifest file which I saved as manifest.json in the same directory as the HTML file. You can create your own manifest file using the Web App Manifest Generator. Be sure to adjust the icon file names in your own manifest file and in the link tags in the HTML as we see here:

{ "short_name": "Weather Clock", "name": "Weather Clock by Shearspire Media", "icons": { "src": "icons/launcher-icon-1x.png", "type": "image/png", "sizes": "48x48" }, { "src": "icons/launcher-icon-2x.png", "type": "image/png", "sizes": "96x96" }, { "src": "icons/launcher-icon-128.png", "type": "image/png", "sizes": "128x128" }, { "src": "icons/launcher-icon-152.png", "type": "image/png", "sizes": "152x152" }, { "src": "icons/launcher-icon-4x.png", "type": "image/png", "sizes": "192x192" } ], "orientation": "landscape", "display": "standalone", "start_url": "index.html" }

We also need a set of square PNG images at 192px, 152px, 128px, 96px, and 48px for the home screen icon. Save these into an icons folder within the same folder as your HTML file. Use the file names found in the manifest. The Web App Manifest Generator will create icons in all the required sizes other than 48px by uploading a single 512 x 512 pixel image. Here is the simple icon I made:

Home screen icon for my Weather Clock.

Finally, we need to add a bunch of meta and link tags in the head of the HTML file to make this all work. Here is the completed index.html file code including all the head tags you can’t see on CodePen.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes"> <link rel="manifest" href="manifest.json"> <link rel="apple-touch-icon" sizes="48x48" href="icons/launcher-icon-1x.png"> <link rel="apple-touch-icon" sizes="96x96" href="icons/launcher-icon-2x.png"> <link rel="apple-touch-icon" sizes="128x128" href="icons/launcher-icon-128.png"> <link rel="apple-touch-icon" sizes="152x152" href="icons/launcher-icon-152.png"> <link rel="apple-touch-icon" sizes="192x192" href="icons/launcher-icon-4x.png"> <title>Weather Clock by ShearSpire Media</title> <script src="clock.js"></script> <link rel="stylesheet" type="text/css" href="clock.css"> </head> <body> /* Clock markup */ </body> </html>

The visitor can now tap the share button on the iPhone and choose “Add to Home Screen.” An icon will appear that will launch the clock as a full-screen standalone app. Enjoy!

Another Option: IP Address Location

See the Pen Clock and Weather IP by Steven Estrella (@sgestrella) on CodePen.

If the user’s exact location isn’t a requirement, we could avoid the Geolocation API entirely and get the approximate location using any of several IP address services. In the demo above, a JSON object is received from extreme-ip-lookup.com to get the approximate GPS location of the user. That displays the city and region values found in the JSON instead of the GPS coordinates. It should be clear to the user in this case that the weather location is a neighboring town.

Since IP information is part of the normal request for a web page, an argument could be made that there is no ethical problem with displaying IP location information without user permission. That eliminates the need for the GPS button altogether. I actually switched the final app to use the IP address location feature with geolocation only as a fallback in the event the IP location service is down. I also added more weather information, custom background images, and custom weather icons to correspond to current weather conditions. The custom icons are available at this Pen. The final app is available here on my ShearSpireMedia.com site. I also created a Pen that generates a starry sky for night mode that can be used to make a night background.

That’s a wrap!

We covered a lot of ground in this article, but hopefully it gives you an idea that:

  • We can teach an old device new tricks.
  • The Geolocation API isn’t all that scary.
  • Fetching and using data from an external API is useful.
  • Using a small PHP file is one easy way to hide your API key from prying eyes.
  • Working with user permissions is a good (and often required) practice.

Like I mentioned earlier, a serverless solution for storing data would be ideal here, so if you have any thoughts on that — or really any ideas or questions at all — please let me know in the comments!

The post How I Built a GPS-Powered Weather Clock With My Old iPhone 4 appeared first on CSS-Tricks.

5 Ways To Optimise Your App For High User Retention

Usability Geek - Wed, 01/16/2019 - 1:25pm
According to mobile app user retention rates from Statista, 55% of mobile app users will abandon an app one month after downloading it. That number grows to 68% after three months. Localytics gives...
Categories: Web Standards

How I’ve Been Using Notion Personally and Professionally

Css Tricks - Wed, 01/16/2019 - 12:53pm

I use Notion quite a bit, both personally and professionally.

In a sense, it's just an app for keeping documents in one place: little notes, to-do lists, basic spreadsheets, etc. I like the native macOS Notes app just fine. It's quick and easy, it's desktop and mobile, it syncs... but there are enough limitations that I wanted something better. Plus, I wanted something team-based and web-friendly (shared URLs!) and Notion hits those nails on the head.

Here's a bunch of ways to use Notion as well as some scattered random notes and ideas about it.

Workspaces are your teams

The word "workspace" almost makes it seem like you could or should use them as your top-level organization structure within a team. Like different projects would use different workspaces. But I'd say: don't do that. Workspaces are teams, even if it's a party of you and only you.

Pricing is billed by workspace. Team members are organized by workspace. Search is scoped by workspace. Switching workspaces isn't too difficult, but it's not lightning fast, either. I'd say it's worth honoring those walls and keeping workspaces to a minimum. It's almost like Slack. It's easy to get Too-Many-Slack'd, so best to avoid getting Too-Many-Notion'd.

Meeting notes

We have a weekly all-hands meeting at CodePen where we lay out what we've done and what we're going to do. It's nice to have that as a document so it can include links, notes, comments, embeds, etc.

Those notes don't disappear next week — we archive them as a historical record of everything we do.

Publishing and advertising schedules

I like looking at a spreadsheet-like document to see upcoming CSS-
Tricks articles with their statuses:

But that same exact document can be viewed as a calendar as well, if that's easier to look at:

There can be all sorts of views for the same table of content, which is a terrific feature:

Knowledge bases

This might be the easiest selling point for Notion. I'm sure a lot of companies have a whole bunch of documents that get into how the company works, including employee databases, coding guidelines, deployment procedures, dashboards to other software, etc. Sometimes that works as a wiki, but I've never seen a lovely setup for this kind of thing. Notion works fantastically as a collaborative knowledge base.

Public documents

I can make a document public, and even open it to public comments with the flip of a switch.

Another super fun thing in Notion is applying a header image and emoji, which gives each document a lot of personality. It's done in a way that can't really be screwed up and made into a gross-looking document. Here's an example where I've customized the page header — and look at the public URL!

I've also used that for job postings:

It's also great for things like public accessibility audits where people can be sent to a public page to see what kinds of things are being worked on with the ability to comment on items.

Quick, collaborative documents

Any document can be shared. I can create a quick document and share it with a particular person easily. That could be a private document shared only with team members, or with someone totally outside the team. Or I can make the document publicly visible to all.

I use Notion to create pages to present possibilities with potential sponsorship partners, then morph that into a document to keep track of everything we're doing together.

We use a show calendar for ShopTalk episodes. Each show added to the calendar automatically creates a page that we use as collaborative show notes with our guests.

It's worth noting that a Notion account is required to edit a document. So anyone that's invited will have to register and be logged in. Plus, you'll need to share it with the correct email address so that person can associate their account with that address.

Blog post drafts

I've been trying to keep all my blog post drafts in Notion. That way, they can easily be shared individually and I can browse all the collected ideas at once.

Exporting posts come out as Markdown too, and that's great for blog post drafts because it translates nicely:

Private sub-team documents

Being able to share documents with specific people is great. For example, we have a Founder's Meetings section on CodePen:

There are probably a million more things

Notion is simply documents with interesting blocks. Simple, but brilliant. For me, it can replace and consolidate things like Trello and other kanban tools, lightweight project management platforms, GitHub issues (if you don't need the public-ness), wikis, Google Docs and Spreadsheets, and even simple one-off public websites.

Here's a website dedicated to other people's interesting Notion pages.

What I want from Notion

I'd love to see Notion's web app links open in their desktop app instead of the web. I prefer the app because I have plenty of browser tabs open as it is. It's gotta be possible to do this with a browser extension. There used to be "Paws" for Trello and there was a browser extension that would open Trello links in that app, so there is prior precedent out there.

I'd also like Notion to explore a tabs feature. I constantly need more than one document open at a time and right now the only way to do that is with multiple windows. There is some back-and-forth arrow action that's possible, but it would be interesting to see native tabs or native window splitting somehow.

I'd love to see some performance upgrades too. It's not terribly bad, but working in Notion is so ubiquitous and important in my day-to-day that I'd love for it to feel more instantaneous than it currently does.

The post How I’ve Been Using Notion Personally and Professionally appeared first on CSS-Tricks.

Making Movies With amCharts

Css Tricks - Wed, 01/16/2019 - 5:44am

In this article, I want to show off the flexibility and real power of amCharts 4. We’re going to learn how to combine multiple charts that run together with animations that form a movie experience. Even if you’re only interested in creating a different kind of animation that has nothing to do with charts, you can still use this library, since it’s more than making charts. The core of amCharts is made to help with everything SVG: creation, layout, animation — basically a library that makes working with SVG fun!

Here’s the kind of thing I’m talking about. It's actually a demonstration of seven different charts animated together. We’ll walk through this together, covering how it works and how to re-create it so you can have amCharts in your tool belt the next time you’re working with charts or complex animations.

See the Pen React Hook: setEffect example by amCharts team (@amcharts) on CodePen.

First, let’s outline the stages of the movie

There’s a lot going on in the movie. Let’s break it up into digestible parts that allow us to parse out what’s going on and re-create those parts under the hood.

Here’s the gist of what we’re working with:

  1. The initial animations and states
  2. The pie chart pops up
  3. The pie chart morphs to a country
  4. The plane flies to some other country
  5. The plane becomes big and flies away
  6. The column chart appears and bends to a radar column chart
The initial animations and states

The first thing we’re hit is a pie chart rising from the depths with a curved line wrapped around it. There’s nothing special about the pie chart at this point, but we’ll cover it in the next section.

But what about that curved line? Remember, we make charts, so this line is simply a XY chart with a single line on it. All the other details — grid, labels, tick marks, etc. — are hidden. So, what we’re really looking at is a stripped-down line chart!

Setting up the line and pie chart animations

amCharts calls the lines on this chart a line series. A line series has a variable called tensionX and, in this case, it’s been set to 0.75, making for a curvy line. We have to think of tension like we would a rope that is being held by two people and both ends: the tighter the rope is pulled, the greater the tension; conversely, the tension gets looser as the two ends let up. That 0.75 value is a taking a quarter of a unit away from the initial value (1), creating less tension.

// Creates the line on the chart var lineSeries = lineChart.series.push(new am4charts.LineSeries()); lineSeries.dataFields.dateX = "date"; lineSeries.dataFields.valueY = "value"; lineSeries.sequencedInterpolation = true; lineSeries.fillOpacity = 0.3; lineSeries.strokeOpacity = 0; lineSeries.tensionX = 0.75; Loosens the tension to create a curved line lineSeries.fill = am4core.color("#222a3f"); lineSeries.fillOpacity = 1;

Initially, all the values of the series are the same: a flat line. Then, we set valueY value of the line’s animation to 80, meaning it pops up to the eights row of the chart height — that will make plenty of room for the pie when it comes in.

// Defines the animation that reveals the curved line lineSeries.events.on("shown", function(){ setTimeout(showCurve, 2000) }); // Sets the animation properties and the valueY so the line bounces up to // 80 on the chart's y-axis function showCurve() { lineSeries.interpolationEasing = am4core.ease.elasticOut; lineSeries.dataItems.getIndex(3).setValue("valueY", 80, 2000); setTimeout(hideCurve, 2000); } // This is the initial state where the line starts at 30 on the y-axis // before it pops up to 80 function hideCurve() { lineSeries.interpolationEasing = am4core.ease.elasticOut; lineSeries.dataItems.getIndex(3).setValue("valueY", 30, 2000); setTimeout(showCurve, 2000); }

Here is the line chart alone so we have a better visual for how that looks:

See the Pen deconstructing amCharts movie, stage 1 by amCharts team (@amcharts) on CodePen.

Next, the pie chart pops up from the bottom. Like a line series, amCharts includes a pie series and it has a dy property that we can set to hidden with a state of 400.

// Make the circle to show initially, meaning it will animate its properties from hidden state to default state circle.showOnInit = true; // Set the circle's easing and the duration of the pop up animation circle.defaultState.transitionEasing = am4core.ease.elasticOut; circle.defaultState.transitionDuration = 2500; // Make it appear from bottom by setting dy of hidden state to 300; circle.hiddenState.properties.dy = 300;

To illustrate this concept, here is a demo with that simple circle in place of a pie chart:

See the Pen deconstructing amCharts movie, initial animation by amCharts team (@amcharts) on CodePen.

A brief overview of amChart states

The idea of states in amCharts is this: you can have any number of custom states on any sprite. Then, instead of creating multiple animations with a slew of various different properties, state is changed from one to another and all the required properties that are set on the target state will animate from current values to the new state values.

Any numeric, percentage or color property of a sprite can be animated. By default, sprites have hidden and default states baked in. The hidden state is applied initially and followed by the revealed state, which is the default. There are other states, of course, like hover, active, disabled, among others, including custom states. Here is another demo showing a slice chart with innerRadius, radius and fill animating on hover:

See the Pen deconstructing amCharts movie, understanding states by amCharts team (@amcharts) on CodePen.

The pie chart pops up

Here is a demo of a basic pie chart. After some time, we’ll hide all the slices, except one, then show them all again.

See the Pen deconstructing amCharts movie, pie chart by amCharts team (@amcharts) on CodePen.

If you look at the code in the demo, you will see some of properties of the slices are customized via pieSeries.slices.template or pieSeries.labels.template. Most of the customization, of course, can be done using themes (amCharts 4 supports using multiple themes at the same time), but since we only need to change a few properties, we can use a template. We’re using a pie chart type and all of the slices of the pie series will be created using the provided template which passes any of the inherited properties we use from the template onto our pie chart.

// Call included themes for styling and animating am4core.useTheme(am4themes_amchartsdark); am4core.useTheme(am4themes_animated); // ... // Call the Pie Chart template var pieChart = mainContainer.createChild(am4charts.PieChart);

What if you want to set a custom color for the chart’s font? We can do this by adding a field in the data, like fontColor. That allows us to set custom colors there and then tell the label template that it should look at the field to inform the color property value.

// Define custom values that override one provided by the template pieChart.data = [{ "name": "[bold]No[/]", "fontColor": am4core.color("#222a3f"), "value": 220, "tickDisabled":true }, { "name": "Hm... I don't think so.", "radius":20, "value": 300, "tickDisabled":false }, { "name": "Yes, we are using amCharts", "value": 100, "labelDisabled": true, "tickDisabled":true }];

Any property of a sprite can be customized like this. And even later, after the chart is initialized, we can change any property via the template, or if we need to access some individual object, we can get any value using something like series.slices.getIndex(3) to isolate it.

To summarize: there isn't a single object on the chart that can’t be customized or accessed, changed, even after the chart is built. We’re working with a lot of flexibility!

The pie chart morphs into a country

I’ll be blunt: There is no way to morph a whole pie chart or some other complex object to the shape of a country. In amCharts 4, one polygon can morph into another one. And there are prebuilt methods that simply morph a polygon to a circle or to a rectangle. Here’s what we’ll do:

  • First, we hide all the slices of a pie chart, except one. This makes effectively transforms the remaining slice into a circle.
  • Then we animate the innerRadius property to 0, and the slice becomes a true circle.
  • There’s already a map chart at this moment, but it is hidden out of view. While it hides, we zoom into a selected country and morph it into a circle as well.
  • Next, we’ll show the country (which is now a circle) and hide the pie chart (which looks like the same circle at this time).
  • Finally, we morph the country back to its original shape.

Here is a simplified demo where we zoom in to the country, morph it to a circle, then morph it back to its default state:

See the Pen deconstructing amCharts movie, morphing by amCharts team (@amcharts) on CodePen.

Inspect that code. Note that all the methods we call, like zoomToMapObject, morphToCircle or morphBack, return an Animation object. An animation object dispatches events like animationstarted, animationprogress or animationended and we can attach listeners to them. This ensures that one animation is triggered only after another one is finished. And, if we change the duration of an animation, we won't need to adjust timers accordingly, because events will handle it. In amCharts 4, Sprites, Components, DataItems, Animations, and other objects have an event dispatcher object which regulate any events. You can add listeners for these events and use them to make your applications super interactive.

The plane flies from one country to another

At one point, an airplane surfaces at London on a map chart and travels all the way to Silicon Valley.

It might look complex and scary, but it’s using a lot of the concepts we’ve already covered and the features come standard with the map chart included in amCharts:

  • MapImageSeries is created and sprites (circles and labels) are mapped to the actual longitude latitude coordinates of both cities.
// Create first image container var imageSeries = mapChart.series.push(new am4maps.MapImageSeries()); // London properties var city1 = imageSeries.mapImages.create(); // London's latitude/longitude city1.latitude = 51.5074; city1.longitude = 0.1278; // prevent from scaling when zoomed city1.nonScaling = true; // New York City properties var city2 = imageSeries.mapImages.create(); // NY latitude/longitude city2.latitude = 40.7128; city2.longitude = -74.0060; // Prevent scaling when zoomed city2.nonScaling = true;
  • MapLineSeries, like the standard line series we saw earlier, creates a line between the cities based on the coordinates that are provided, going from one map image to another. By default, the line is drawn so that it follows the shortest distance between the objects. That happens to be a curved line in this case. We could make it a straight line if we’d like.
// Create the map line series var lineSeries = mapChart.series.push(new am4maps.MapLineSeries()); var mapLine = lineSeries.mapLines.create(); // Tell the line to connect the two cities (latitudes/longitudes an be used alternatively) mapLine.imagesToConnect = [city1, city2] // Draw the line in dashes mapLine.line.strokeDasharray = "1,1"; mapLine.line.strokeOpacity = 0.2;
  • An object (plane) is added to the MapLine and it moves between the endpoints of the line by animating the plane’s position property from 0 to 1.
// Create the plane container var planeContainer = mapLine.lineObjects.create(); planeContainer.position = 0; // Set the SVG path of a plane for the sprite var plane = planeContainer.createChild(am4core.Sprite); planeContainer.nonScaling = false; planeContainer.scale = 0.015; // SVG plane illustration plane.path = "M71,515.3l-33,72.5c-0.9,2.1,0.6,4.4,2.9,4.4l19.7,0c2.8,0,5.4-1,7.5-2.9l54.1-39.9c2.4-2.2,5.4-3.4,8.6-3.4 l103.9,0c1.8,0,3,1.8,2.3,3.5l-64.5,153.7c-0.7,1.6,0.5,3.3,2.2,3.3l40.5,0c2.9,0,5.7-1.3,7.5-3.6L338.4,554c3.9-5,9.9-8,16.2-8c24.2,0,85.5-0.1,109.1-0.2c21.4-0.1,41-6.3,59-17.8c4.2-2.6,7.9-6.1,11.2-9.8c2.6-2.9,3.8-5.7,3.7-8.5c0.1-2.8-1.1-5.5-3.7-8.5c-3.3-3.7-7-7.2-11.2-9.8c-18-11.5-37.6-17.7-59-17.8c-23.6-0.1-84.9-0.2-109.1-0.2c-6.4,0-12.3-2.9-16.2-8L222.6,316.6c-1.8-2.3-4.5-3.6-7.5-3.6l-40.5,0c-1.7,0-2.9,1.7-2.2,3.3L237,470c0.7,1.7-0.5,3.5-2.3,3.5l-103.9,0c-3.2,0-6.2-1.2-8.6-3.4l-54.1-39.9c-2.1-1.9-4.7-2.9-7.5-2.9l-19.7,0c-2.3,0-3.8,2.4-2.9,4.4l33,72.5C72.6,507.7,72.6,511.8,71,515.3z"; plane.fill = am4core.color("#eeeab5"); plane.horizontalCenter = "middle"; plane.verticalCenter = "middle";

Here is a demo of a plane flying from London to New York:

See the Pen deconstructing amCharts movie, map part by amCharts team (@amcharts) on CodePen.

Notice that the plane becomes bigger when it hits the line’s halfway point? This is done with three additional lines of code we can stick at the end.

// Make the plane to be bigger in the middle of the line planeContainer.adapter.add("scale", function(scale, target) { return (0.07 - 0.10 * (Math.abs(0.5 - target.position))) / mapChart.zoomLevel; })

We’re using a method that called an adapter, which is another super-powerful feature of amCharts 4. In this case, the adapter modifies the scale property (0.07 to 0.10), based on planes position (0.5).

The plane becomes big and flies away

When our plane reaches the target city (Silicon Valley in the full movie), we scale and rotate it to become horizontal and big.

At the same moment, we create another chart (the SlicedChart type) and add a PictorialSeries to it. The series share’s the same path as the plane, which creates a mask for the slices. We can use any SVG path here.

When the slices are shown, we want the plane to fly away:

This happens by animating the chart object’s dx property.

flyAway() function flyAway(){ var animation = pictorialChart.animate({property:"dx", to:2000}, 1500, am4core.ease.quadIn).delay(2000); animation.events.on("animationended", flyIn); } function flyIn(){ var animation = pictorialChart.animate({property:"dx", from:-2000, to:0}, 1500, am4core.ease.quadOut); animation.events.on("animationended", flyAway); }

Here is a demo of a Sliced chart:

See the Pen deconstructing amCharts movie, pictorial series by amCharts team (@amcharts) on CodePen.

The trail of a plane is again made with a line series, similar to the one we had in the beginning. This time, it's a combination of two separate series: one with positive and another with negative values. When a series has the sequencedInterpolation property set to true, the animation happens with some delay for each data value and we get an effect like this:

See the Pen deconstructing amCharts movie, plane trail by amCharts team (@amcharts) on CodePen.

var series1 = chart.series.push(new am4charts.LineSeries()) series1.dataFields.dateX = "date"; series1.dataFields.valueY = "value1"; series1.sequencedInterpolation = true; series1.fillOpacity = 1; series1.tensionX = 0.8; series1.stroke = am4core.color("#222a3f") series1.fill = am4core.color("#222a3f")

Then there’s the silhouette of a cityscape that scrolls horizontally as the plane passes by:

See the Pen deconstructing amCharts movie, city passing by by amCharts team (@amcharts) on CodePen.

This uses the same chart as the plane trail. We basically add another value axis to the chart and create a column series:

// Add a new axis to the chart var valueAxis = chart.yAxes.push(new am4charts.ValueAxis()); // ... shortened for brevity // Configure the column series var series = chart.series.push(new am4charts.ColumnSeries()) series.dataFields.dateX = "date"; series.dataFields.valueY = "value"; series.sequencedInterpolation = true; series.fillOpacity = 1; series.fill = am4core.color("#222a3f"); series.stroke = am4core.color("#222a3f") // Establish the columns at full width series.columns.template.width = am4core.percent(100);

Then we update the background to gradient:

chart.background.fillOpacity = 0.2; var gradient = new am4core.LinearGradient(); gradient.addColor(am4core.color("#222a3f")); gradient.addColor(am4core.color("#0975da")); gradient.rotation = -90; chart.background.fill = gradient;

And finally, we zoom in on the chart to half of the total range so that we can slowly change the zoom level later to create the moving city effect.

function startZoomAnimation(){ // Animate the start and end values slowly to make it look like the city is moving var animation = dateAxis.animate([{property:"start", from:0, to:0.5}, {property:"end", from:0.5, to:1}], 15000, am4core.ease.linear); animation.events.on("animationended", startZoomAnimation); }

Here is all the code, without the trail part for brevity:

am4core.useTheme(am4themes_amchartsdark); am4core.useTheme(am4themes_animated); // Main container var mainContainer = am4core.create("introchart", am4core.Container); mainContainer.width = am4core.percent(100); mainContainer.height = am4core.percent(100); var chart = mainContainer.createChild(am4charts.XYChart); chart.padding(0, 0, 0, 0) chart.zIndex = 20; var data = []; var date = new Date(2000, 0, 1, 0, 0, 0, 0); for (var i = 0; i < 40; i++) { var newDate = new Date(date.getTime()); newDate.setDate(i + 1); var value = Math.abs(Math.round(((Math.random() * 100 - i + 10) / 10)) * 10) data.push({ date: newDate, value: value }); } chart.data = data; chart.zoomOutButton.disabled = true; chart.seriesContainer.zIndex = -1; chart.background.fillOpacity = 0.2; var gradient = new am4core.LinearGradient(); gradient.addColor(am4core.color("#222a3f")); gradient.addColor(am4core.color("#0975da")); gradient.rotation = -90; chart.background.fill = gradient; var dateAxis = chart.xAxes.push(new am4charts.DateAxis()); dateAxis.renderer.grid.template.location = 0; dateAxis.renderer.ticks.template.disabled = true; dateAxis.renderer.axisFills.template.disabled = true; dateAxis.renderer.labels.template.disabled = true; dateAxis.rangeChangeEasing = am4core.ease.sinIn; dateAxis.renderer.inside = true; dateAxis.startLocation = 0.5; dateAxis.endLocation = 0.5; dateAxis.renderer.baseGrid.disabled = true; dateAxis.tooltip.disabled = true; dateAxis.renderer.line.disabled = true; dateAxis.renderer.grid.template.strokeOpacity = 0.07; var valueAxis = chart.yAxes.push(new am4charts.ValueAxis()); valueAxis.tooltip.disabled = true; valueAxis.renderer.ticks.template.disabled = true; valueAxis.renderer.axisFills.template.disabled = true; valueAxis.renderer.labels.template.disabled = true; valueAxis.renderer.inside = true; valueAxis.min = 0; valueAxis.max = 100; valueAxis.strictMinMax = true; valueAxis.tooltip.disabled = true; valueAxis.renderer.line.disabled = true; valueAxis.renderer.baseGrid.disabled = true; valueAxis.renderer.grid.template.strokeOpacity = 0.07; var series = chart.series.push(new am4charts.ColumnSeries()) series.dataFields.dateX = "date"; series.dataFields.valueY = "value"; series.sequencedInterpolation = true; series.fillOpacity = 1; series.fill = am4core.color("#222a3f"); series.stroke = am4core.color("#222a3f") series.columns.template.width = am4core.percent(100); chart.events.on("ready", startZoomAnimation); function startZoomAnimation(){ // Animate the start and end values slowly to make it look like city is moving var animation = dateAxis.animate([{property:"start", from:0, to:0.5}, {property:"end", from:0.5, to:1}], 15000, am4core.ease.linear); animation.events.on("animationended", startZoomAnimation); } The column chart appears and bends to a radar column chart

Can you guess what happens in the final scene? The initial chart (which looks like a regular column chart) is actually what’s called a radar chart with a very small arc between the chart’s startAngle (269.9°) and endAngle (270.1°) properties.

var radarChart = mainContainer.createChild(am4charts.RadarChart); // ... Chart properties go here radarChart.startAngle = 269.9; radarChart.endAngle = 270.1;

The total arc angle is only 0.2° degrees and that's why the radius of a chart becomes very big and tough tell it apart from a regular XY chart. And all we do to bend the chart is animate the start and end angles. I told you… we can literally animate everything, including angles!

radarChart.events.on("ready", bend); function bend() { var animation = radarChart.animate([{ property: "startAngle", to: 90 }, { property: "endAngle", to: 450 }], 3500, am4core.ease.cubicIn).delay(1000); animation.events.on("animationended", unbend); } function unbend() { var animation = radarChart.animate([{ property: "startAngle", to: 269.9 }, { property: "endAngle", to: 270.1 }], 3500, am4core.ease.cubicIn).delay(500); animation.events.on("animationended", bend); }

Here’s that bending animation in all its glory:

See the Pen deconstructing amCharts movie, bending the chart by amCharts team (@amcharts) on CodePen.

OK, we are done!

Oh, but there is one last, important thing I would like to mention: Containers. All charts and other non-chart objects in this movie are contained in a single div element. Initially, we created mainConatainer and arranged all the objects inside it. Containers support horizontal, vertical, grid and absolute layouts. Fixed or absolute positions can be used for a container's children, and containers can be nested inside other containers. They can be aligned horizontally or vertically, set to a fixed or absolute width or height… and so on. And did I mentioned, that amCharts has built-in date, number and text formatters? Seriously, I will stop here.

As a part of the amCharts team, I often hear comments like, "but you can do all of this with d3.” Yes, you are probably right. But there are still real benefits we’re working with here — fewer lines of code, time spent writing it, and a relatively simple startup. All the animation is made up of 1,000 lines of code, so this is also a pretty lightweight resource.

But, I’m really interested in what you think. Have you tried amCharts before and have examples to show off? How about questions about getting started? Or maybe you’re not sold on the concept altogether and want to chat the pros and cons? Let’s hear it in the comments!

The post Making Movies With amCharts appeared first on CSS-Tricks.

Escaping Gridlock: When And How To Break A Grid Layout

Usability Geek - Tue, 01/15/2019 - 1:02pm
Barring a freshly cleaned whiteboard or the latest version of Sketch, one of the most invaluable tools in a user experience designer’s toolbox is the grid layout. Ancient as design itself, grid...
Categories: Web Standards

How Well Do You Know CSS Layout?

Css Tricks - Tue, 01/15/2019 - 4:54am

The difference between a CSS good experience and a long frustrating one is oftentimes a matter of a few small details. CSS is indeed nuanced. One of the most common areas where I see struggles is layout. Personally, I like to study patterns. I notice that I tend to use a small group of patterns to solve the majority of my layout problems. This article is about those CSS patterns I use to get myself through layout challenges. It is also about approaching situations agnostically, regardless of the CSS methodologies used, whether that’s SMACSS, BEM, or even the hot topic of CSS-in-JS because they all focus on the properties themselves rather than architecture, organization, or strategy.

Just for fun, let’s start with a test

We’ll use a platform that I happen to have made called Questionable.io and I’ve used it to create a test that we’ll get to below. Don’t worry, there is no personal data collected, results are anonymous and it’s totally free.

The purpose of the test is to see if you can recognize specific CSS behaviors and problems in context without first being presented with the material. I didn’t set out to make the test difficult, but CSS layout nuances tend to be somewhat complex, especially without having a lot of exposure to them. Remember, this all for fun. The results are not an indication of your awesomeness, but hopefully you get value out of it.

The test is 10 questions and should take 10 minutes or less.

Take CSS Layout Quiz

Interested in the test but don’t want to take it? Here’s a link to the questions with their correct answers.

Done already? Great! Let’s go over the questions one-by-one to get a better understanding of the layout patterns that are covered in the test.

Question 1: Box Model

Learning the Box Model should be high priority on anyone’s list. While this CSS-Tricks Box Model Article may be a bit old, don’t underestimate its value and relevance to modern CSS. The Box Model is prerequisite knowledge for almost every CSS topic related to layout.

This particular question is testing how to get the Box Model’s computed width. The box clearly has width: 100px; but it turns out that the default rules of the Box Model apply width properties to the content layer of the box. The computed width (how wide is rendered on the page) is the sum of the content layer, padding layer, and border layer. For this reason, the answer is 112px:

.box { width: 100px; /* Take this */ height: 50px; padding: 5px; /* Plus this x2 for left and right */ border: 1px solid red; /* Plus this x2 for left and right */ background-color: red; /* = 112px of computed width */ }

If you’ve encountered a situation where the last column or tab in a UI wraps down to the next line and you were confident that five tabs (all set to width: 20%;) adds up to 100%, then it’s very possible that this was the issue. Five tabs at 20% width does add up to 100%, but if there’s padding and/or borders involved, those will add width there won’t be room for the last tab to fit on the same line.

Around the time of CSS3 being introduced, a new tool called box-sizing came to CSS. This allows us to change what layer of the Box Model we want width to apply. For example, we can do box-sizing: border-box; which means we want any width rules to apply to the outside of the border layer instead of the content layer. In this test question, if box-sizing: border-box; had been applied, the computed width would have been 100px.

This is old news for some of you but a good reminder for pros and novices alike.

There are a number of articles on the Box Model and how to use box-sizing as a reset, so it’s applied to your entire project all at once. Box Sizing and Inheriting box-sizing Probably Slightly Better Best-Practice are two great articles right on CSS-Tricks to get started.

Question 2: Borders are pushy

The second test question could almost be considered "Part Two" of the first question. Remember, it’s one thing to read, "The Box Model has layers and they all contribute to the calculated width and hight." It’s another to be able to recognize a Box Model problem in a real situation. This particular problem is somewhat of a classic among those who have been doing CSS for a while. It stems from the fact that borders take up space and will push things around since they are a part of the Box Model. Introducing borders during a state-transition, like :hover, will mean that boxes get bigger and thus push subsequent boxes down. It can also create a jittery experience:

See the Pen CSS-Tricks: Borders are Dimension by Brad Westfall (@bradwestfall) on CodePen.

Out of all the possible solutions in the test question, doing border: 2px solid transparent on the initial "un-hovered" state would be the only one that fixes the problem. box-sizing doesn’t fix this problem because we are not explicitly setting a height. If we had, then the border would be factored on the inside of the height and there would be no shift — but this wasn’t the case.

There are also other solutions that weren’t mentioned as possible answers. One is faux borders with box-shadow and the other is to use outline instead of border. Either of those would have resulting in no shifting during state changes because they are not layers in the Box Model. Here’s another CSS-Tricks article to read more about these solutions

Keep in mind that outline does not support border-radius.

Question 3: Absolute position vs. fixed position

Aside from knowing when to use each and how they differ in visual behavior, it’s also very important to know the rules for how each positioning method attaches to a parent element with its top, right, bottom, or left properties.

First, let’s review Containing Block. The short definition is that a Containing Block is most often the parent of any given element. However, the rules for Containing Block are different between absolute and fixed elements:

1. For absolute elements: The Containing Block is the nearest ancestor parent that is not static. For example, when an element is absolute-positioned, and contains top, right, bottom, or left properties, it will position relative to any parent that has a position of absolute, relative, fixed, or sticky.
2. For fixed elements: The Containing Block is the viewport, regardless of any parents that have position values other than static. Also, the scrolling behavior is different than absolute in that position: fixed; elements stay "fixed" to the viewport as it scrolls, hence the name.

Many developers believe absolute-positioned elements only seek the nearest position: relative; parent. This is a common misconception simply because position: relative is most often paired with position: absolute; to make a Containing Block. The reason it’s commonly used is because relative keeps the parent in flow which is often the desirable behavior. There are times though that the Containing Block of an absolute positioned element is also absolute positioned. This is totally okay depending on the situation. If all parents are static, then the absolute positioned element will attach to the viewport — but in a way that scrolls with the viewport:

See the Pen CSS-Tricks: Position Absolute Scrolling by Brad Westfall (@bradwestfall) on CodePen.

There is a lesser-known caveat to the two rules above: Anytime a parent has a transform property (among a few others) with a value other than none, then that parent will become the Containing Block for absolute- and fixed-positioned elements. This can be observed in this Pen where the notice is position: fixed; and the parent has transform but only when hovered:

See the Pen CSS-Tricks: Containing Blocks by Brad Westfall (@bradwestfall) on CodePen.

Question 4: Parent and first/last child collapsing margins

This is one of those CSS details that can really bite you if you don’t know how it works. There is a CSS concept called Collapsing Margins and many people are familiar with the form of it called Adjacent Siblings Collapsing Margins. However, there is another form of it called Parent and First/Last Child Collapsing Margins which is lesser known. Here is a demo of both:

See the Pen CSS-Tricks: Collapsing Margins by Brad Westfall (@bradwestfall) on CodePen.

Each paragraph tag has a top and bottom margin of 1em that are provided by the browser. So far, that’s the easy part. But why is the gap between the paragraphs not 2em (the sum of the top and bottom)? This is called Adjacent Sibling Collapsing Margins. The margins overlap such that the larger of the two margins will be the total gap size, thus the gap in this case is 1em.

There’s something else happening that’s a little strange though. Did you notice that the top margin of the first paragraph doesn’t create a gap between it and the blue container div? Instead of a gap, it’s almost like it "contributes" the margin to the parent div as if the div had the top margin. This is called Parent and First/Last Child Collapsing Margins. This form of Collapsing Margins will not happen in some circumstances if the parent has any of these:

  • Top/Bottom padding of any value bigger than 0.
  • Top/Bottom border of any width bigger than 0.
  • Block Formatting Context, which can be created by things like overflow: hidden; and overflow: auto;).
  • display: flow-root (not well supported).

When I have the pleasure of explaining this small CSS detail to people and solving it with padding or border, the response is almost always, "what about padding or border of 0?" Well, that doesn’t work because the value must be a positive integer.

In the previous example, just 1px of padding allows us to toggle between using and preventing Parent/Child Collapsing Margins. The gap that shows up between the first/last paragraphs and the parent is the 1px of padding but now the margin is being factored to the inside of the container since the padding layer creates a barrier preventing collapsing margins.

Regarding the question, I’m confident you can see what the problem is in this UI:

See the Pen CSS-Tricks: Parent/Child Collapsing Margins by Brad Westfall (@bradwestfall) on CodePen.

The first .comment (without the .moderator class) is experiencing Collapsing Margins. Even without looking at the code, we can see that the moderator comment has a border and the non-moderator one does not. In the question, there were actually three answers that were considered correct. Each one is actually already applied in the source of the Pen, they're just commented out.

One reason why this form of Collapsing Margins isn’t as widely known as the others is the wide array of ways we can "accidentally" avoid it. Flexbox and grid items create a Block Formatting Context, so we don’t see this form of Collapsing Margins there. If our "comments" UI were a real project, chances are we would have had padding on all four coordinates to create spacing all the way around, which would fix any Collapsing Margins for us. As rare as it might be, I wouldn’t want you to spend a whole day scratching you head on this one, so it’s good to keep in your thoughts when working with layout.

Here are some CSS-Tricks articles on this subject:

Question 5: Percent of what?

When it comes to using percentage units, the percent is said to be based on the Containing Block’s width or height (usually related to the parent). As we stated earlier, an element with transform will become a Containing Block, so when an element is using transform, the percentage units (for transform only) are based on its own size rather than the parent.

In this example, we can see that 50% means two different things depending on context. The first red block has margin-left: 50%; and the second red block is using transform: translateX(50%);:

See the Pen CSS-Tricks - Percentage and Transform by Brad Westfall (@bradwestfall) on CodePen.

Question 6: The Box Model strikes again... what a hangover!

Just when you thought we were done talking about Box Model...

See the Pen CSS-Tricks: Left: 0 Right: 0 by Brad Westfall (@bradwestfall) on CodePen.

The hangover stems from the fact that we are using width: 100%; on the footer and also adding padding. The container is 500px wide which means the footer's content layer (being 100%) is 500px wide before padding is applied to the outside of that layer.

The hangover can be fixed with one of these two common techniques:

  1. Use box-sizing on the footer directly or via a reset, like we discussed earlier.
  2. Remove the width and do left: 0; right: 0; instead. This is a great use case for doing a left value and a right value at the same time. Doing so will avoid Box Model issues because the width will use its default value auto to take up any available space between paddings and borders when left: 0; right: 0; are set.

One of the options was "Remove the padding on the footer." This would technically work to fix the hangover because the content layer being 100% would have no padding or border to expand it beyond the width of the container. But I think this solution is the wrong approach because we shouldn’t have to change our UI to accommodate Box Model issues that are easily avoided.

The reality for me is that I always have box-sizing: border-box; as apart of my reset. If you also do this, then perhaps you don’t see this problem often. But I still like to do the left: 0; right: 0; trick anyways because, over time, it has been more stable (at least in my experience) than having to deal with Box Model issues arising from width: 100%; on positioned elements.

Question 7: Centering absolute and fixed elements

Now we’re really starting to combine all the material from above with the centering of absolute and fixed elements:

See the Pen CSS-Tricks: Modal (Lightbox) Centering by Brad Westfall (@bradwestfall) on CodePen.

Since we’ve already covered most of the material in this test question, I’ll simply point out that horizontal and vertical centering can be done "the old school way" with negative margins or the newer "kinda old school but still good" way of doing transforms. Here is an amazing CSS-Tricks guide on all things centering.

It used to be said that if we know the width and height of the box, then we should use negative margins because they’re more stable than transitions, which were new to browsers. Now that transitions are stable, I use them almost all the time for this, unless I need to avoid a Containing Block.

Also know that we can’t use any margin: auto; tricks for this because we need modals to "hover" over the content which is why position is typically used to them out of Normal Flow.

Speaking of which, let’s move on to the next question, which deals with centering with Normal Flow.

Question 8: Centering elements with Normal Flow

Flexbox brought us many amazing tools for solving difficult layout problems. Before it’s release, it was said that vertical centering was one of the most difficult things to do in CSS. Now it’s somewhat trivial:

.parent { display: flex; } .child { margin: auto; }

See the Pen CSS-Tricks: Flexbox Centering (Vertical and Horizontal) by Brad Westfall (@bradwestfall) on CodePen.

Notice that with flexbox items, the margin: auto is being applied to top, right, bottom, and left to center vertically and horizontally. Doing vertical centering with auto didn't work in the past with block-level elements which is why doing margin: 0 auto is common.

Question 9: Calculate mixed units

Using calc() is perfect when two units that we can’t add up on our own need to be mixed or when we need to make fractions easier to read. This test question asks us to figure out what calc(100% + 1em) would be based on the fact that the width of the div is 100px. This was a little tricky because it actually doesn't matter that the div is 100px wide. The percent is based on the parent's width so the answer is Whatever 100% of the containing block's (parent's) width is plus 1em.

There are a few key places where I see myself regularly reaching for calc(). One is anytime I want to offset something by 100% but also add a fixed amount of extra space. Dropdown menus can be a good example of this:

See the Pen CSS Tricks: Calculate Mixed Units by Brad Westfall (@bradwestfall) on CodePen.

The trick here is that we want to make a "dropdown system" where the dropdown menu can be used with different trigger sizes (in this case, two different size buttons). We don’t know what the height of the trigger will be but we do know that top: 100%; will placed at the top of our menu and at the very bottom of the trigger. If every menu needs to be at the bottom of their respective trigger, plus .5em, then that can happen with top: calc(100% + 0.5em);. Sure, we could use top: 110%; as well, but that extra 10% would be context-dependent based on the height of the trigger and the container.

Question 10: Negative margins

Unlike positive margins that push away from their siblings, negative margins pull them closer together without moving the sibling elements. This final test question offers two solutions that technically work to eliminate the double border in our button group, but I strongly prefer the negative margins technique because removing borders would make it much more challenging to do certain tricks like this hover effect:

See the Pen CSS Tricks: Negative Margins with Button Groups by Brad Westfall (@bradwestfall) on CodePen.

The effect is a "common border" that is shown between the buttons. Buttons can't actually share a common border so we need this negative margin trick to make the two borders overlap. Then I'm using a z-index to manage which border I want to be on top depending on the hover state. Note that z-index is useful here even without absolute positioning, but I did have to do position: relative. If I had used the technique to remove the left border of the second button, this effect would have been more difficult to pull off.

It all adds up!

There is one last demo I want to show you that utilizes many tricks we’ve discussed so far. The task is to create UI tiles that expand all the way to the left and right edges of the container with gutters. By tiles, I mean the ability to have a list of blocks that wraps down to the next line when there’s no more space. Hover over the tiles to see the full effect:

See the Pen CSS-Tricks: Flexbox Tiles (Edge-to-Edge) by Brad Westfall (@bradwestfall) on CodePen.

The hurdle with this task is the gutters. Without gutters, it would be trivial to get the tiles to touch the left and right edge of the container. The problem is that the gutters will be created by margin, and when we add margin to all sides of the tile, we create two problems:

  1. Having three tiles with width: 33.33%; in combination with margin will mean three tiles cannot fit on one row. While box-sizing will allow us to have padding and borders on the .tile which will be contained within 33.33%, it will not help us with margins — that means the computed width of the three tiles will be more than 100%, forcing the last one down to the next line.
  2. Tiles on the far left and right side will no longer touch the edges of the container.

The first problem can be solved with calc((100% / 3) - 1em). That’s 33.33% minus the left and right margins of each tile. Adjacent Sibling Collapsing Margins don’t apply here because there is no such thing as Collapsing Margins when it comes to left and right margin. As a result, the horizontal distance between each tile is the sum of the two margins (1em). It also doesn’t apply in this case with the top and bottom margins because the first tile and the fourth tile are technically not Adjacent Siblings, even though they happen to be right next to each other visually.

With the calc() trick, three tiles are able to fit on a row, but they still don’t extend to edges of the container. For that, we can use negative margins in the amount equal to the left and right margin of each tile. The green dotted line in the example is the container where we will apply negative margins to draw out the tiles to match the edge of the surrounding content. We can see that how it extends into its parent’s padding area (the main element). That’s okay because negative margins don’t push neighboring elements around.

The end result is that the tiles have nice gutters that extend edge-to-edge so that they align to the neighboring paragraph tags outside the tiles.

There’s a lot of ways to solve tiles (and they usually come with their own pros and cons). For example, there's a rather elegant solution using CSS Grid discussed by Heydon Pickering which is responsive using a technique that mimics container queries (but with Grid magic). Ultimately, his Grid solution to tiles is much nicer than the flexbox solution I presented, but it also has less browser support. Nonetheless, the flexbox solution is still a great way to demo all the tricks from this article at the same time.

You may already be familiar with Heydon's work. He's known for creating clever tricks like the Lobotomized Owl selector. If you're not familiar, it's certainly worth knowing and I have a video where I talk about it.

Summary

I stated at the start that I tend to look for patterns when solving problems. This article isn’t necessarily about the exact demo scenarios from above; it’s more about a set of tools that can be used to solve these and many other layout problems that we are all likely to come across. I hope these tools take you far and I look forward to hearing your contributions in the comments.

By the way, there are a number of excellent resources that cover the Box Model in thorough detail, most notably ones by Rachel Andrews and Jen Simmons that are certainly worth checking out. Rachel even has a newsletter completely dedicated to layout.

  • Box Alignment Cheatsheet - Great resource with visuals that highlight the various properties that affect how elements are aligned, either by themselves or relative to other elements.
  • Jen Simmons Labs - A slew of helpful posts, demos and experiments using modern layout methods.

The post How Well Do You Know CSS Layout? appeared first on CSS-Tricks.

CSS doesn’t suck

Css Tricks - Tue, 01/15/2019 - 4:50am

I'm not so protective of CSS that I'm above hearing it criticized, but I'm certainly in agreement here. CSS does not suck. I love how the post is framed to hype up current CSS features the way features of other languages and tools are hyped:

Imagine if a tech dude walked on stage at a conference and said the following:

“This declarative language will gracefully continue on failure, allow you to write global and scoped code, and it will work across your entire front-end stack, whether it’s rendered by a framework, a CMS or a static HTML file”

... Now, if I make a slight amendment to that, the reception would probably be the exact opposite.

“CSS will gracefully continue on failure, allow you to write global and scoped code, and it will work across your entire front-end stack, whether it’s rendered by a framework, a CMS or a static HTML file”

Direct Link to ArticlePermalink

The post CSS doesn’t suck appeared first on CSS-Tricks.

Syndicate content
©2003 - Present Akamai Design & Development.