Tag: Sharing

Just Sharing My Gulpfile

Seemingly out of the blue, the Gulp processing I had set up for this site started to have a race condition. I’d run my watch command, change some CSS, and the processing would sometimes leave behind some extra files that were meant to be cleaned up during the processing. Like the cleanup tasks happened before the files landed in the file system (or something… I never really got to the bottom of it).

Nevermind about the specifics of that bug. I figured I’d go about solving it by upgrading things to use Gulp 4.x instead of 3.x, and running things in the built-in gulp.series command, which I thought would help (it did).

Getting Gulp 4.x going was a heck of a journey for me, involving me giving up for a year, then reigniting the struggle and ultimately getting it fixed. My trouble was that Gulp 4 requires a CLI version of 2.x while Gulp 3, for whatever reason, used a 3.x version. Essentially I needed to downgrade versions, but after trying a billion things to do that, nothing seemed to work, like there was a ghost version of CLI 3.x on my machine.

I’m sure savvier command-line folks could have sussed this out faster than me, but it turns out running command -v gulp will reveal the file path of where Gulp is installed which revealed /usr/local/share/npm/bin/gulp for me, and deleting it manually from there before re-installing the lastest version worked in getting me back down to 2.x.

Now that I could use Gulp 4.x, I re-wrote my gulpfile.js into smaller functions, each fairly isolated in responsibility. Much of this is pretty unique to my setup on this site, so it’s not meant to be some boilerplate for generic usage. I’m just publishing because it certainly would have been helpful for me to reference as I was creating it.

Things my particular Gulpfile does

  • Runs a web server (Browsersync) for style injection and auto-refreshing
  • Runs a file watcher (native Gulp feature) for running the right tasks on the right files and doing the above things
  • CSS processing
    • Sass > Autoprefixer > Minify
    • Break stylesheet cache from the templates (e.g. <link href="style.css?BREAK_CACHE">
    • Put style.css in the right place for a WordPress theme and clean up files only needed during processing
  • JavaScript processing
    • Babel > Concatenate > Minify
    • Break browser cache for the <script>s
    • Clean up unused files created in processing
  • SVG processing
    • Make an SVG sprite (a block of <symbol>s
    • Name it as a sprite.php file (so it can be PHP-included in a template) and put it somewhere specific
  • PHP processing
    • Update the Ajax call in the JavaScript to cache-bust when the ads change

Code dump!

const gulp = require("gulp"),   browserSync = require("browser-sync").create(),   sass = require("gulp-sass"),   postcss = require("gulp-postcss"),   autoprefixer = require("autoprefixer"),   cssnano = require("cssnano"),   del = require("del"),   babel = require("gulp-babel"),   minify = require("gulp-minify"),   concat = require("gulp-concat"),   rename = require("gulp-rename"),   replace = require("gulp-replace"),   svgSymbols = require("gulp-svg-symbols"),   svgmin = require("gulp-svgmin");  const paths = {   styles: {     src: ["./scss/*.scss", "./art-direction/*.scss"],     dest: "./css/"   },   scripts: {     src: ["./js/*.js", "./js/libs/*.js", "!./js/min/*.js"],     dest: "./js/min"   },   svg: {     src: "./icons/*.svg"   },   php: {     src: ["./*.php", "./ads/*.php", "./art-direction/*.php", "./parts/**/*.php"]   },   ads: {     src: "./ads/*.php"   } };  /* STYLES */ function doStyles(done) {   return gulp.series(style, moveMainStyle, deleteOldMainStyle, done => {     cacheBust("./header.php", "./");     done();   })(done); }  function style() {   return gulp     .src(paths.styles.src)     .pipe(sass())     .on("error", sass.logError)     .pipe(postcss([autoprefixer(), cssnano()]))     .pipe(gulp.dest(paths.styles.dest))     .pipe(browserSync.stream()); }  function moveMainStyle() {   return gulp.src("./css/style.css").pipe(gulp.dest("./")); }  function deleteOldMainStyle() {   return del("./css/style.css"); } /* END STYLES */  /* SCRIPTS */ function doScripts(done) {   return gulp.series(     preprocessJs,     concatJs,     minifyJs,     deleteArtifactJs,     reload,     done => {       cacheBust("./parts/footer-scripts.php", "./parts/");       done();     }   )(done); }  function preprocessJs() {   return gulp     .src(paths.scripts.src)     .pipe(       babel({         presets: ["@babel/env"],         plugins: ["@babel/plugin-proposal-class-properties"]       })     )     .pipe(gulp.dest("./js/babel/")); }  function concatJs() {   return gulp     .src([       "js/libs/jquery.lazy.js",       "js/libs/jquery.fitvids.js",       "js/libs/jquery.resizable.js",       "js/libs/prism.js",       "js/babel/highlighting-fixes.js",       "js/babel/global.js"     ])     .pipe(concat("global-concat.js"))     .pipe(gulp.dest("./js/concat/")); }  function minifyJs() {   return gulp     .src(["./js/babel/*.js", "./js/concat/*.js"])     .pipe(       minify({         ext: {           src: ".js",           min: ".min.js"         }       })     )     .pipe(gulp.dest(paths.scripts.dest)); }  function deleteArtifactJs() {   return del([     "./js/babel",     "./js/concat",     "./js/min/*.js",     "!./js/min/*.min.js"   ]); } /* END SCRIPTS */  /* SVG */ function doSvg() {   return gulp     .src(paths.svg.src)     .pipe(svgmin())     .pipe(       svgSymbols({         templates: ["default-svg"],         svgAttrs: {           width: 0,           height: 0,           display: "none"         }       })     )     .pipe(rename("icons/sprite/icons.php"))     .pipe(gulp.dest("./")); } /* END SVG */  /* GENERIC THINGS */ function cacheBust(src, dest) {   var cbString = new Date().getTime();   return gulp     .src(src)     .pipe(       replace(/cache_bust=\d+/g, function() {         return "cache_bust=" + cbString;       })     )     .pipe(gulp.dest(dest)); }  function reload(done) {   browserSync.reload();   done(); }  function watch() {   browserSync.init({     proxy: "csstricks.local"   });   gulp.watch(paths.styles.src, doStyles);   gulp.watch(paths.scripts.src, doScripts);   gulp.watch(paths.svg.src, doSvg);   gulp.watch(paths.php.src, reload);   gulp.watch(paths.ads.src, done => {     cacheBust("./js/global.js", "./js/");     done();   }); }  gulp.task("default", watch);

Problems / Questions

  • The worst part is that it doesn’t break cache very intelligently. When CSS changes, it breaks the cache on all stylesheets, not just the relevant ones.
  • I’d probably just inline SVG icons with PHP include()s in the future rather than deal with spriting.
  • The SVG processor breaks if the original SVGs have width and height attributes, which seems wrong.
  • Would gulp-changed be a speed boost? As in, only looking at files that have changed instead of all files? Or is it not necessary anymore?
  • Should I be restarting gulp on gulpfile.js changes?
  • Sure would be nice if all the libs I used were ES6-compatible so I could import stuff rather than having to manually concatenate.

Always so much more that can be done. Ideally, I’d just open-source this whole site, I just haven’t gotten there yet.

The post Just Sharing My Gulpfile appeared first on CSS-Tricks.


, ,

The Communal Cycle of Sharing

What I’m interested in this year is how we’re continuing to expand on tools, services, and shared side projects to collectively guide where we take the web next, and the way we’re sharing that.

So many other mediums—mostly analog ones—have been around for ages and have a deeper history. In the grand scheme of things, the web, and thus the job of building for it, are still pretty new. We talk about open source and licenses, the ebbs and flows of changes of web-related (public and for-profit) education, the never-ending conversation about what job titles we think web builders should have, tooling, and so much more. The communal experience of this field is what makes and keeps this all very interesting.

The sharing aspect is equally, if not more important, than the building itself.

I thoroughly enjoy seeing browsers share more of their new builds include. I’m grateful that we have multiple browsers to work with and not one monolithic giant. I’m obsessed that websites like CodePen and Glitch exist and that sharing is the main goal of those services, and that people’s lives have changed because of an experiment they created or came across. I’m touched that people make things for their own needs and feel inclined to share that code or that design process with someone else. I’m also glad to see design tools focus on collaboration and version control to improve our process.

Recently, I was thinking about how delightful it was to set up Netlify to host my site and also use it for client work at thoughtbot. I used to try to understand how to set up staging previews based on pull requests or scratch my head as I tried to understand why the “s” in “https” was so important. But now Netlify helps with those things so much that it’s almost like that side of their service was built for people like me.

But, it gets better. In a community Slack, a fellow web builder says “Hey, Netlify’s a great tool and my static site generator now works on it.”

So then here I am at midnight and wide awake, starting a new demo repository using 11ty.

Fast forward, and another fellow builder shares their project Hylia, which makes starting an 11ty site on Netlify delightfully easy.

And all of this is freely available to use.

Putting this all together, I realize we’re moving from a place where we’re not just sharing what we have, we’re working to build and improve on what others have built. And then sharing that, and the cycle continues. In a way, we’ve been doing this all along but it feels more noticeable now. In a way, we’re not just building websites, but building and iterating the way we build websites, and that is exciting.

The post The Communal Cycle of Sharing appeared first on CSS-Tricks.


, ,

UX Considerations for Web Sharing

From trashy clickbait sites to the most august of publications, share buttons have long been ubiquitous across the web. And yet it is arguable that these buttons aren’t needed. All mobile browsers — Firefox, Edge, Safari, Chrome, Opera Mini, UC Browser, Samsung Internet — make it easy to share content directly from their native platforms. They all feature a built-in button to bring up a “share sheet” — a native dialog for sharing content. You can also highlight text to share an excerpt along with the link.

A collage of various share buttons from sites across the web.
The ubiquitous share button, as seen at the BBC, Wired, BuzzFeed, PBS, The Wall Street Journal and elsewhere.

Given that users can share by default, are custom buttons taking up unnecessary space and potentially distracting users from more important actions? And do people actually use them?

A (unscientific) poll of 12,500 CSS-Tricks readers found that 60% of its readers never used custom share buttons. That was in 2014 and native methods for sharing have only improved since then. A more recent poll from Smashing Magazine found much the same thing.

Users come with varying technological proficiency. Not everybody knows their way around there own mobile phone or browser meaning some users would struggle to find the native share button. It’s also worth thinking about what happens on desktop. Desktop browsers generally (with Safari as one exception) offer no built-in sharing functionality — users are left to copy and paste the link into their social network of choice.

Some data suggests that clickthrough rates are relatively low. However, clickthrough rates aren’t the best metric. For technically savvy users aware of how to share without assistance, the buttons can still act as a prompt — a visual reminder to share the content. Regardless of how the link is ultimately shared, a custom share button can still provide a cue, or a little nudge to elicit the share. For this reason, measuring click rates on the buttons themselves may not be entirely fair — people may see the button, feel encouraged to share the content, but then use the browsers built-in share button. A better metric would be whether shares increase after the addition of share buttons, regardless of how they’re shared.

We’ve established that having a share button is probably useful. Websites have traditionally featured separate buttons for two or three of the most popular social networks. With a new-ish API, we can do better. While browser support is currently limited to Chrome for Android and Safari, those two browsers alone make up the vast majority of web traffic.

The Web Share API

The Web Share API offers a simple way to bring up a share sheet — the native bit of UI that’s used for sharing. Rather than offering a standard list of popular social networks to share to (which the user may or may not be a member of), the options of the share sheet are catered to the individual. Only applications they have installed on their phone will be shown. Rather than a uniform list, the user will be shown only the option to share on networks they actually use — whether that be Twitter and Facebook or something more esoteric.

Not showing the user irrelevant networks is obviously a good thing. Unfortunately, this is counterbalanced by the fact that some users visit social media websites rather than downloading them as apps. If you use twitter.com, for example, but haven’t installed the Twitter application natively, then Twitter will not be listed as a sharing option. Currently, only native apps are listed but PWAs will be supported in the future.

websharebutton.addEventListener("click", function() {   navigator.share({     url: document.URL,     title: document.title,     text: "lorem ipsum..."   }); });

The API requires user interaction (such as a button click as shown in the above code) to bring up the share sheet. This means you can’t do something obnoxious like bring up the share sheet on page load.

The text might be a short excerpt or a summation of the page. The title is used when sharing via email but will be ignored when sharing to social networks.

Comparing the share sheets of Android and iPhone.
Native sharesheet dialog on Android (left) and iOS (right). The apps listed here are dependent on which apps you have installed on your device.

Sharing on desktop

While we are pretty happy with the Web Share API for mobile, its implementation for desktop is currently limited to Safari and leaves a lot to be desired. (Chrome is planning to ship support eventually, but there is no clear timescale).

The provided options — Mail, Message, Airdrop, Notes, Reminders — omit social networks. Native apps for Twitter and Facebook are common on phones, but rare on other devices.

Instead of relying on the Web Share API for desktop, its relatively common to have a generic share button that opens a modal that offers more multiple sharing options. This is the approach adopted by YouTube, Instagram and Pinterest, among others.

Comparing Instagram and YouTube share options on desktop.
Instagram (left) compared to YouTube (right)

Facebook and Twitter account for the vast majority of sharing online, so offering an exhaustive list of social networks to choose from doesn’t feel necessary. (An option for Instagram would be ideal, but it is currently not technically possible to share to Instagram from a website.) It is also relatively common to include an email option. For anyone using a web-based email client like gmail.com or outlook.com rather than the operating system’s default email application, this is problematic.

Many people make use of web-based email client’s gmail.com or outlook.com. A share-by-email button will open the operating system’s default email application. Users will be greeted by a prompt to set this up, which is far more effort than simply copy and pasting the URL. It is therefore advisable to omit the email option and instead include a button to copy the link to the clipboard, which is only infinitesimally easier than doing a copy in the address bar with the keyboard.

Screenshot of the share options offered by Mac's email application, including iCloud, Exchange, Google, Yahoo and AOL.
A prompt to set up the default email application on Mac

Prompting the user to set up an application they never use is far more effort than simply copy and pasting a URL into my preferred email client.

Choosing a share icon

Grid of various share icons in different variations.
There have been plenty of other share icons over the years.

There is no universal standardized share icon — far from it. While the Android symbol might not be recognizable to long-term iPhone users, the iOS icon is problematic. It is identical to the download icon — but with the arrow in the opposite direction, which would imply uploading, not sharing.

Where I work at giffgaff, we polled 69 of our colleagues on whether they recognized the current iOS icon or the current Android icon as representing sharing. The Android icon was an overwhelming winner with 58 votes. While our sample did include iPhone users, some long-term iPhone users may not be familiar with this symbol (even though it has been adopted by some websites). Then there is the forward arrow, an icon that was abandoned by Apple, but adopted elsewhere. Reminiscent of the icon for forwarding an email, this symbol has been made recognizable by its usage on youtube.com. The icon was adopted by Microsoft in 2017 after A/B testing found a high level of familiarity.

It’s also possible to take a contextual approach. Twitter will change the icon used depending on the platform of the user. This approach is also taken by the icon library Ionicons.

Showing the same tweet on both Android and iOS
Android (left) and Mac/iOS (right)

Given the lack of a universally understood icon, this seems like a good approach. Alternatively, make sure to include a label alongside the icon to really spell things out to the user.

The post UX Considerations for Web Sharing appeared first on CSS-Tricks.