Tag: Devs

Static Site Generators vs. CMS-powered Websites: How to Keep Marketers and Devs Happy

(This is a sponsored post.)

Many developers love working with static site generators like Gatsby and Hugo. These powerful yet flexible systems help create beautiful websites using familiar tools like Markdown and React. Nearly every popular modern programming language has at least one actively developed, fully-featured static site generator.

Static site generators boast a number of advantages, including fast page loads. Quickly rendering web pages isn’t just a technical feat, it improves audience attraction, retention, and conversion. But as much as developers love these tools, marketers and other less technical end users may struggle with unfamiliar workflows and unclear processes.

The templates, easy automatic deploys, and convenient asset management provided by static site generators all free up developers to focus on creating more for their audiences to enjoy. However, while developers take the time to build and maintain static sites, it is the marketing teams that use them daily, creating and updating content. Unfortunately, many of the features that make static site generators awesome for developers make them frustrating to marketers.

Let’s explore some of the disadvantages of using a static site generator. Then, see how switching to a dynamic content management system (CMS) — especially one powered by a CRM (customer relationship management) platform — can make everyone happy, from developers to marketers to customers.

Static Site Generator Disadvantages

Developers and marketers typically thrive using different workflows. Marketers don’t usually want to learn Markdown just to write a blog post or update site copy — and they shouldn’t need to. 

Frankly, it isn’t reasonable to expect marketers to learn complex systems for everyday tasks like embedding graphs or adjusting image sizes just to complete simple tasks. Marketers should have tools that make it easier to create and circulate content, not more complicated.

Developers tend to dedicate most of their first week on a project to setting up a development environment and getting their local and staging tooling up and running. When a development team decides that a static site generator is the right tool, they also commit to either configuring and maintaining local development environments for each member of the marketing team or providing a build server to preview changes.

Both approaches have major downsides. When marketers change the site, they want to see their updates instantly. They don’t want to commit their changes to a Git repository then wait for a CI/CD pipeline to rebuild and redeploy the site every time. Local tooling enabling instant updates tends to be CLI-based and therefore inaccessible for less technical users.

This does not have to devolve into a prototypical development-versus-marketing power struggle. A dynamic website created with a next-generation tool like HubSpot’s CMS Hub can make everyone happy.

A New Generation of Content Management Systems

One reason developers hold static site generators in such high regard is the deficiency of the systems they replaced. Content management systems of the past were notorious for slow performance, security flaws, and poor user experiences for both developers and content creators. However, some of today’s CMS platforms have learned from these mistakes and deficiencies and incorporated the best static site generator features while developing their own key advantages.

A modern, CMS-based website gives developers the control they need to build the features their users demand while saving implementation time. Meanwhile, marketing teams can create content with familiar, web-based, what-you-see-is-what-you-get tools that integrate directly with existing data and software.

For further advantages, consider a CRM-powered solution, like HubSpot’s CMS Hub. Directly tied to your customer data, a CRM-powered site builder allows you to create unique and highly personalized user experiences, while also giving you greater visibility into the customer journey.

Content Management Systems Can Solve for Developers

Modern content management systems like CMS Hub allow developers to build sites locally with the tools and frameworks they prefer, then easily deploy to them their online accounts. Once deployed, marketers can create and edit content using drag-and-drop and visual design tools within the guardrails set by the developers. This gives both teams the flexibility they need and streamlines workflows. 

Solutions like CMS Hub also replace the need for unreliable plugins with powerful serverless functions. Serverless functions, which are written in JavaScript and use the NodeJS runtime, allow for more complex user interactions and dynamic experiences. Using these tools, developers can build out light web applications without ever configuring or managing a server. This elevates websites from static flyers to a modern, personalized customer experience without piling on excess developer work. 

While every content management system will have its advantages, CMS Hub also includes a built-in relational database, multi-language support, and the ability to build dynamic content and login pages based on CRM data. All features designed to make life easier for developers.

Modern CMS-Based Websites Make Marketers Happy, Too

Marketing teams can immediately take advantage of CMS features, especially when using a CRM-powered solution. They can add pages, edit copy, and even alter styling using a drag-and-drop editor, without needing help from a busy developer. This empowers the marketing team and reduces friction when making updates. It also reduces the volume of support requests that developers have to manage.

Marketers can also benefit from built-in tools for search engine optimization (SEO), A/B testing, and specialized analytics. In addition to standard information like page views, a CRM-powered website offers contact attribution reporting. This end-to-end measurement reveals which initiatives generate actual leads via the website. These leads then flow seamlessly into the CRM for the sales team to close deals.

CRM-powered websites also support highly customized experiences for site users. The CRM behind the website already holds the customer data. This data automatically synchronizes because it lives within one system as a single source of truth for both marketing pages and sales workflows. This default integration saves development teams time that they would otherwise spend building data pipelines.

Next Steps

Every situation is unique, and in some cases, a static site generator is the right decision. But if you are building a site for an organization and solving for the needs of developers and marketers, a modern CMS may be the way to go. 

Options like CMS Hub offer all the benefits of a content management system while coming close to matching static site generators’ marquee features: page load speed, simple deployment, and stout reliability. But don’t take my word for it. Create a free CMS Hub developer test account and take it for a test drive.

The post Static Site Generators vs. CMS-powered Websites: How to Keep Marketers and Devs Happy appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.


, , , , , , , ,


I did this thing for Honeypots YouTube Channel. I had heard of Honeypot through these mini documentaries they have done, like about Vue.js, GraphQL, and Ember.js. They do a great job, so I was happy to shoot them over some answers to questions for this series.

Here’s a TLDR-ish transcript:

What’s the best way to stay up to date with new technologies?

Don’t worry about it much. If you’re actively building websites and solving problems that come up day to day, you’re doing the job and that’s what’s important. If you’re really worried you’re only ever using outdated tech, go to a conference once a year and see what people are talking about.

What are your top tips for career advancement?

Writing! You don’t have to blog, even though I like that idea. You can write to your co-workers, or even keep a private log. Writing really opens doors and makes you a better thinker.

What strengths are most important for a developer?

Communication trumps raw technical skill. One developer alone can never do as much as a high functioning team, and communication is what makes a team high functioning.

What what the proudest moment of your career?

I tend to look back at things that took a long time and didn’t involve just me. CodePen will be 10 years old next year. That’s something to be proud of.

When did you realize you wanted to be a developer?

I had a good teacher in high school. I’m sure they don’t even remember me, but I was highly into the computer programming class they taught. I’d come to school early to use the computer lab. I’d stay after school. I’d take my study halls there. Working on a program, with the guidance of that teacher, was deeply fun. While I ended up abandoning computer science in college for art, my career now I find was a way to marry my love of computer nerdery and art.

The post Honeypot DEVS ANSWER appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, ,

There’s a good reason why experienced devs say “it depends” so often

I feel like Jerod Santo really understood what I was trying to say in Weaved Webs, when I was trying to cover the emerging WordPress (“versus”) Jamstack conversation.

If you asked El Duderino if you should go Jamstack he’d probably tell you, “It’s a complicated case. Lotta ins. Lotta outs. Lotta what-have-yous. Lotta strands to keep in my head, man.”

This conversation is very much not over. Look at what I get to do:

Direct Link to ArticlePermalink

The post There’s a good reason why experienced devs say “it depends” so often appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , , , , ,

The Making of: Netlify’s Million Devs SVG Animation Site

The following article captures the process of building the Million Developers microsite for Netlify. This project was built by a few folks and we’ve captured some parts of the process of building it here- focusing mainly on the animation aspects, in case any are helpful to others building similar experiences.

Building a Vue App out of an SVG

The beauty of SVG is you can think of it, and the coordinate system, as a big game of battleship. You’re really thinking in terms of x, y, width, and height.

<div id="app">    <app-login-result-sticky v-if="user.number" />    <app-github-corner />     <app-header />     <!-- this is one big SVG -->    <svg id="timeline" xmlns="http://www.w3.org/2000/svg" :viewBox="timelineAttributes.viewBox">      <!-- this is the desktop path -->      <path        class="cls-1 timeline-path"        transform="translate(16.1 -440.3)"        d="M951.5,7107..."      />      <!-- this is the path for mobile -->      <app-mobilepath v-if="viewportSize === 'small'" />       <!-- all of the stations, broken down by year -->      <app2016 />      <app2017 />      <app2018 />      <app2019 />      <app2020 />       <!-- the 'you are here' marker, only shown on desktop and if you're logged in -->      <app-youarehere v-if="user.number && viewportSize === 'large'" />    </svg>  </div> 

Within the larger app component, we have the large header, but as you can see, the rest is one giant SVG. From there, we broke down the rest of the giant SVG into several components:

  • Candyland-type paths for both desktop and mobile, shown conditionally by a state in the Vuex store
  • There are 27 stations, not including their text counterparts, and many decorative components like bushes, trees, and streetlamps, which is a lot to keep track of in one component, so they’re broken down by year
  • The ‘you are here’ marker, only shown on desktop and if you’re logged in

SVG is wonderfully flexible because not only can we draw absolute and relative shapes and paths within that coordinate system, we can also draw SVGs within SVGs. We just need to defined the x, y, width and height of those SVGs and we can mount them inside the larger SVG, which is exactly what we’re going to do with all these components so that we can adjust their placement whenever needed. The <g> within the components stands for group, you can think of them a little like divs in HTML.

So here’s what this looks like within the year components:

<template>  <g>    <!-- decorative components -->    <app-tree x="650" y="5500" />    <app-tree x="700" y="5550" />    <app-bush x="750" y="5600" />     <!-- station component -->    <app-virtual x="1200" y="6000" xSmall="50" ySmall="15100" />    <!-- text component, with slots -->    <app-text      x="1400"      y="6500"      xSmall="50"      ySmall="15600"      num="20"      url-slug="jamstack-conf-virtual"    >      <template v-slot:date>May 27, 2020</template>      <template v-slot:event>Jamstack Conf Virtual</template>    </app-text>     ...  </template>  <script> ...  export default {  components: {    // loading the decorative components in syncronously    AppText,    AppTree,    AppBush,    AppStreetlamp2,    // loading the heavy station components in asyncronously    AppBuildPlugins: () => import("@/components/AppBuildPlugins.vue"),    AppMillion: () => import("@/components/AppMillion.vue"),    AppVirtual: () => import("@/components/AppVirtual.vue"),  }, }; ... </script>

Within these components, you can see a number of patterns:

  • We have bushes and trees for decoration that we can sprinkle around viax and y values via props
  • We can have individual station components, which also have two different positioning values, one for large and small devices
  • We have a text component, which has three available slots, one for the date, and two for two different text lines
  • We’re also loading in the decorative components synchronously, and loading those heavier SVG stations async

SVG Animation

Header animation for Million Devs

The SVG animation is done with GreenSock (GSAP), with their new ScrollTrigger plugin. I wrote up a guide on how to work with GSAP for their latest 3.0 release earlier this year. If you’re unfamiliar with this library, that might be a good place to start.

Working with the plugin is thankfully straightforward, here is the base of the functionality we’ll need:

import { gsap } from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger.js"; import { mapState } from "vuex";  gsap.registerPlugin(ScrollTrigger);  export default {  computed: {    ...mapState([      "toggleConfig",      "startConfig",      "isAnimationDisabled",      "viewportSize",    ]),  },  ...  methods: {    millionAnim() {      let vm = this;      let tl;      const isScrollElConfig = {        scrollTrigger: {          trigger: `.million$ {vm.num}`,          toggleActions: this.toggleConfig,          start: this.startConfig,        },        defaults: {          duration: 1.5,          ease: "sine",        },      };    }  },  mounted() {    this.millionAnim();  }, }; 

First, we’re importing gsap and the package we need, as well as state from the Vuex store. I put the toggleActions and start config settings in the store and passed them into each component because while I was working, I needed to experiment with which point in the UI I wanted to trigger the animations, this kept me from having to configure each component separately.

Those configurations in the store look like this:

export default new Vuex.Store({   state: {     toggleConfig: `play pause none pause`,     startConfig: `center 90%`,   } }

This configuration breaks down to

  • toggleConfig: play the animation when it passes down the page (another option is to say restart and it will retrigger if you see it again), it pauses when it is out of the viewport (this can slightly help with perf), and that it doesn’t retrigger in reverse when going back up the page.
  • startConfig is stating that when the center of the element is 90% down from the height of the viewport, to trigger the animation to begin.

These are the settings we decided on for this project, there are many others! You can understand all of the options with this video.

For this particular animation, we needed to treat it a little differently if it was a banner animation which didn’t need to be triggered on scroll or if it was later in the timeline. We passed in a prop and used that to pass in that config depending on the number in props:

if (vm.num === 1) {   tl = gsap.timeline({     defaults: {       duration: 1.5,       ease: "sine",     },   }); } else {   tl = gsap.timeline(isScrollElConfig); }

Then, for the animation itself, I’m using what’s called a label on the timeline, you can think of it like identifying a point in time on the playhead that you may want to hang animations or functionality off of. We have to make sure we use the number prop for the label too, so we keep the timelines for the header and footer component separated.

tl.add(`million$ {vm.num}`) ... .from(   "#front-leg-r",   {     duration: 0.5,     rotation: 10,     transformOrigin: "50% 0%",     repeat: 6,     yoyo: true,     ease: "sine.inOut",   },   `million$ {vm.num}` ) .from(   "#front-leg-l",   {     duration: 0.5,     rotation: 10,     transformOrigin: "50% 0%",     repeat: 6,     yoyo: true,     ease: "sine.inOut",   },   `million$ {vm.num}+=0.25` );

There’s a lot going on in the million devs animation so I’ll just isolate one piece of movement to break down: above we have the girls swinging legs. We have both legs swinging separately, both are repeating several times, and that yoyo: true lets GSAP know that I’d like the animation to reverse every other alteration. We’re rotating the legs, but what makes it realistic is the transformOrigin starts at the center top of the leg, so that when it’s rotating, it’s rotating around the knee axis, like knees do 🙂

Adding an Animation Toggle

animation toggle

We wanted to give users the ability to explore the site without animation, should they have a vestibular disorder, so we created a toggle for the animation play state. The toggle is nothing special- it updates state in the Vuex store through a mutation, as you might expect:

export default new Vuex.Store({   state: {     ...     isAnimationDisabled: false,   },   mutations: {     updateAnimationState(state) {       state.isAnimationDisabled = !state.isAnimationDisabled     },   ... })

The real updates happen in the topmost App component where we collect all of the animations and triggers, and then adjust them based on the state in the store. We watch the isAnimationDisabled property for changes, and when one occurs, we grab all instances of scrolltrigger animations in the app. We don’t .kill() the animations, which one option, because if we did, we wouldn’t be able to restart them.

Instead, we either set their progress to the final frame if animations are disabled, or if we’re restarting them, we set their progress to 0 so they can restart when they are set to fire on the page. If we had used .restart() here, all of the animations would have played and we wouldn’t see them trigger as we kept going down the page. Best of both worlds!

watch: {    isAnimationDisabled(newVal, oldVal) {      ScrollTrigger.getAll().forEach((trigger) => {        let animation = trigger.animation;        if (newVal === true) {          animation && animation.progress(1);        } else {          animation && animation.progress(0);        }      });    },  }, 

SVG Accessibility

I am by no means an accessibility expert, so please let me know if I’ve misstepped here- but I did a fair amount of research and testing on this site, and was pretty excited that when I tested on my Macbook via voiceover, the site’s pertinent information was traversable, so I’m sharing what we did to get there.

For the initial SVG that cased everything, we didn’t apply a role so that the screenreader would traverse within it. For the trees and bushes, we applied role="img" so the screenreader would skip it and any of the more detailed stations we applied a unique id and title, which was the first element within the SVG. We also applied role="presentation".

<svg    ...    role="presentation"    aria-labelledby="analyticsuklaunch"  >    <title id="analyticsuklaunch">Launch of analytics</title>

I learned a lot of this from this article by Heather Migliorisi, and this great article by Leonie Watson.

The text within the SVG does announce itself as you tab through the page, and the link is found, all of the text is read. This is what that text component looks like, with those slots mentioned above.

<template>  <a    :href="`https://www.netlify.com/blog/2020/08/03/netlify-milestones-on-the-road-to-1-million-devs/#$ {urlSlug}`"  >    <svg      xmlns="http://www.w3.org/2000/svg"      width="450"      height="250"      :x="svgCoords.x"      :y="svgCoords.y"      viewBox="0 0 280 115.4"    >      <g :class="`textnode text$ {num}`">        <text class="d" transform="translate(7.6 14)">          <slot name="date">Jul 13, 2016</slot>        </text>        <text class="e" transform="translate(16.5 48.7)">          <slot name="event">Something here</slot>        </text>        <text class="e" transform="translate(16.5 70)">          <slot name="event2" />        </text>        <text class="h" transform="translate(164.5 104.3)">View Milestone</text>      </g>    </svg>  </a> </template> 

Here’s a video of what this sounds like if I tab through the SVG on my Mac:

If you have further suggestions for improvement please let us know!

The repo is also open source if you want to check out the code or file a PR.

Thanks a million (pun intended) to my coworkers Zach Leatherman and Hugues Tennier who worked on this with me, their input and work was invaluable to the project, it only exists from teamwork to get it over the line! And so much respect to Alejandro Alvarez who did the design, and did a spectacular job. High fives all around. 🙌

The post The Making of: Netlify’s Million Devs SVG Animation Site appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , , ,

CSS Tips for New Devs

Amber Wilson has some CSS Tips for New Devs, like:

It’s not a good idea to fix shortcomings in your HTML with CSS. Fix your HTML first!


You can change CSS right in your browser’s DevTools (to open them, right-click the browser window and choose “inspect” or “inspect element”). The great thing is, none of the styles will be saved so you can experiment here! Another great thing about the DevTools is the “computed styles” tab, because this shows you exactly what styles are currently applied to an element. This can be really helpful when it comes to debugging your CSS!

There are 24 tips there. I “counted” by using DevTools to change the <ul> to an <ol>. 😉

Direct Link to ArticlePermalink

The post CSS Tips for New Devs appeared first on CSS-Tricks.