Archiwum kategorii: CSS

How to Get the Current Page URL in Gatsby

Post pobrano z: How to Get the Current Page URL in Gatsby

This seemingly simple task had me scratching my head for a few hours while I was working on my website. As it turns out, getting the current page URL in Gatsby is not as straightforward as you may think, but also not so complicated to understand.

Let’s look at a few methods of making it happen. But first, you might be wondering why on earth we’d even want to do something like this.

Why you might need the current URL

So before we get into the how, let’s first answer the bigger question: Why would you want to get the URL of the current page? I can offer a few use cases.

Meta tags

The first obvious thing that you’d want the current URL for is meta tags in the document head:

<link rel="canonical" href={url} />
<meta property="og:url" content={url} />

Social Sharing

I’ve seen it on multiple websites where a link to the current page is displayed next to sharing buttons. Something like this (found on Creative Market)

Styling

This one is less obvious but I’ve used it a few times with styled-components. You can render different styles based on certain conditions. One of those conditions can be a page path (i.e. part of the URL after the name of the site). Here’s a quick example:

import React from 'react';
import styled from 'styled-components';

const Layout = ({ path, children }) => (
  <StyledLayout path={path}>
    {children}
  </StyledLayout>
);
    
const StyledLayout = styled.main`
  background-color: ${({ path }) => (path === '/' ? '#fff' : '#000')};
`;

export default Layout;

Here, I’ve created a styled Layout component that, based on the path, has a different background color.

This list of examples only illustrates the idea and is by no means comprehensive. I’m sure there are more cases where you might want to get the current page URL. So how do we get it?

Understand build time vs. runtime

Not so fast! Before we get to the actual methods and code snippets, I’d like to make one last stop and briefly explain a few core concepts of Gatsby.

The first thing that we need to understand is that Gatsby, among many other things, is a static site generator. That means it creates static files (that are usually HTML and JavaScript). There is no server and no database on the production website. All pieces of information (including the current page URL) must be pulled from other sources or generated during build time or runtime before inserting it into the markup.

That leads us to the second important concept we need to understand: Build time vs. runtime. I encourage you to read the official Gatsby documentation about it, but here’s my interpretation.

Runtime is when one of the static pages is opened in the browser. In that case, the page has access to all the wonderful browser APIs, including the Window API that, among many other things, contains the current page URL.

One thing that is easy to confuse, especially when starting out with Gatsby, is that running gatsby develop in the terminal in development mode spins up the browser for you. That means all references to the window object work and don’t trigger any errors.

Build time happens when you are done developing and tell Gatsby to generate final optimized assets using the gatsby build command. During build time, the browser doesn’t exist. This means you can’t use the window object.

Here comes the a-ha! moment. If builds are isolated from the browser, and there is no server or database where we can get the URL, how is Gatsby supposed to know what domain name is being used? That’s the thing — it can’t! You can get the slug or path of the page, but you simply can’t tell what the base URL is. You have to specify it.

This is a very basic concept, but if you are coming in fresh with years of WordPress experience, it can take some time for this info to sink in. You know that Gatsby is serverless and all but moments like this make you realize: There is no server.

Now that we have that sorted out, let’s jump to the actual methods for getting the URL of the current page.

Method 1: Use the href property of the window.location object

This first method is not specific to Gatsby and can be used in pretty much any JavaScript application in the browser. See, browser is the key word here.

Let’s say you are building one of those sharing components with an input field that must contain the URL of the current page. Here’s how you might do that:

import React from 'react';

const Foo = () => {
  const url = typeof window !== 'undefined' ? window.location.href : '';

  return (
    <input type="text" readOnly="readonly" value={url} />
  );
};

export default Foo;

If the window object exists, we get the href property of the location object that is a child of the window. If not, we give the url variable an empty string value.

If we do it without the check and write it like this:

const url = window.location.href;

…the build will fail with an error that looks something like this:

failed Building static HTML for pages - 2.431s
ERROR #95312 
"window" is not available during server-side rendering.

As I mentioned earlier, this happens because the browser doesn’t exist during the build time. That’s a huge disadvantage of this method. You can’t use it if you need the URL to be present on the static version of the page.

But there is a big advantage as well! You can access the window object from a component that is nested deep inside other components. In other words, you don’t have to drill the URL prop from parent components.

Method 2: Get the href property of location data from props

Every page and template component in Gatsby has a location prop that contains information about the current page. However, unlike window.location, this prop is present on all pages.

Quoting Gatsby docs:

The great thing is you can expect the location prop to be available to you on every page.

But there may be a catch here. If you are new to Gatsby, you’ll log that prop to the console, and notice that it looks pretty much identical to the window.location (but it’s not the same thing) and also contains the href attribute. How is this possible? Well, it is not. The href prop is only there during runtime.

The worst thing about this is that using location.href directly without first checking if it exists won’t trigger an error during build time.

All this means that we can rely on the location prop to be on every page, but can’t expect it to have the href property during build time. Be aware of that, and don’t use this method for critical cases where you need the URL to be in the markup on the static version of the page.

So let’s rewrite the previous example using this method:

import React from 'react';

const Page = ({ location }) => {
  const url = location.href ? location.href : '';

  return (
    <input type="text" readOnly="readonly" value={url} />
  );
};

export default Page;

This has to be a top-level page or template component. You can’t just import it anywhere and expect it work. location prop will be undefined.

As you can see, this method is pretty similar to the previous one. Use it for cases where the URL is needed only during runtime.

But what if you need to have a full URL in the markup of a static page? Let’s move on to the third method.

Method 3: Generate the current page URL with the pathname property from location data

As we discussed at the start of this post, if you need to include the full URL to the static pages, you have to specify the base URL for the website somewhere and somehow get it during build time. I’ll show you how to do that.

As an example, I’ll create a <link rel="canonical" href={url} /> tag in the header. It is important to have the full page URL in it before the page hits the browser. Otherwise, search engines and site scrapers will see the empty href attribute, which is unacceptable.

Here’s the plan:

  1. Add the siteURL property to siteMetadata in gatsby-config.js.
  2. Create a static query hook to retrieve siteMetadata in any component.
  3. Use that hook to get siteURL.
  4. Combine it with the path of the page and add it to the markup.

Let’s break each step down.

Add the siteURL property to siteMetadata in gatsby-config.js

Gatsby has a configuration file called gatsby-config.js that can be used to store global information about the site inside siteMetadata object. That works for us, so we’ll add siteURL to that object:

module.exports = {
  siteMetadata: {
    title: 'Dmitry Mayorov',
    description: 'Dmitry is a front-end developer who builds cool sites.',
    author: '@dmtrmrv',
    siteURL: 'https://dmtrmrv.com',
  }
};

Create a static query hook to retrieve siteMetadata in any component

Next, we need a way to use siteMetadata in our components. Luckily, Gatsby has a StaticQuery API that allows us to do just that. You can use the useStaticQuery hook directly inside your components, but I prefer to create a separate file for each static query I use on the website. This makes the code easier to read.

To do that, create a file called use-site-metadata.js inside a hooks folder inside the src folder of your site and copy and paste the following code to it.

import { useStaticQuery, graphql } from 'gatsby';

const useSiteMetadata = () => {
  const { site } = useStaticQuery(
  graphql`
    query {
    site {
      siteMetadata {
      title
      description
      author
      siteURL
      }
    }
    }
  `,
  );
  return site.siteMetadata;
};

export default useSiteMetadata;

Make sure to check that all properties — like title, description, author, and any other properties you have in the siteMetadata object — appear in the GraphQL query.

Use that hook to get siteURL

Here’s the fun part: We get the site URL and use it inside the component.

import React from 'react';
import Helmet from 'react-helmet';
import useSiteMetadata from '../hooks/use-site-metadata';

const Page = ({ location }) => {
  const { siteURL } = useSiteMetadata();
  return (
    <Helmet>
      <link rel="canonical" href={`${siteURL}${location.pathname}`} />
    </Helmet>
  );
};

export default Page;

Let’s break it down.

On Line 3, we import the useSiteMetadata hook we created into the component.

import useSiteMetadata from '../hooks/use-site-metadata';

Then, on Line 6, we destructure the data that comes from it, creating the siteURL variable. Now we have the site URL that is available for us during build and runtime. Sweet!

const { siteURL } = useSiteMetadata();

Combine the site URL with the path of the page and add it to the markup

Now, remember the location prop from the second method? The great thing about it is that it contains the pathname property during both build and runtime. See where it’s going? All we have to do is combine the two:

`${siteURL}${location.pathname}`

This is probably the most robust solution that will work in the browsers and during production builds. I personally use this method the most.

I’m using React Helmet in this example. If you haven’t heard of it, it’s a tool for rendering the head section in React applications. Darrell Hoffman wrote up a nice explanation of it here on CSS-Tricks.

Method 4: Generate the current page URL on the server side

What?! Did you just say server? Isn’t Gatsby a static site generator? Yes, I did say server. But it’s not a server in the traditional sense.

As we already know, Gatsby generates (i.e. server renders) static pages during build time. That’s where the name comes from. What’s great about that is that we can hook into that process using multiple APIs that Gatsby already provides.

The API that interests us the most is called onRenderBody. Most of the time, it is used to inject custom scripts and styles to the page. But what’s exciting about this (and other server-side APIs) is that it has a pathname parameter. This means we can generate the current page URL “on the server.”

I wouldn’t personally use this method to add meta tags to the head section because the third method we looked at is more suitable for that. But for the sake of example, let me show you how you could add the canonical link to the site using onRenderBody.

To use any server-side API, you need to write the code in a file called gatsby-ssr.js that is located in the root folder of your site. To add the link to the head section, you would write something like this:

const React = require('react');
const config = require('./gatsby-config');

exports.onRenderBody = ({ pathname, setHeadComponents }) => {
  setHeadComponents([
    <link rel="canonical" href={`${config.siteMetadata.siteURL}${pathname}`} />,
  ]);
};

Let’s break this code bit by bit.

We require React on Line 1. It is necessary to make the JSX syntax work. Then, on Line 2, we pull data from the gatsby-config.js file into a config variable.

Next, we call the setHeadComponents method inside onRenderBody and pass it an array of components to add to the site header. In our case, it’s just one link tag. And for the href attribute of the link itself, we combine the siteURL and the pathname:

`${config.siteMetadata.siteURL}${pathname}`

Like I said earlier, this is probably not the go-to method for adding tags to the head section, but it is good to know that Gatsby has server-side APIs that make it possible to generate a URL for any given page during the server rendering stage.

If you want to learn more about server-side rendering with Gatsby, I encourage you to read their official documentation.

That’s it!

As you can see, getting the URL of the current page in Gatsby is not very complicated, especially once you understand the core concepts and know the tools that are available to use. If you know other methods, please let me know in the comments!

Resources

The post How to Get the Current Page URL in Gatsby appeared first on CSS-Tricks.

Raw GraphQL Querying

Post pobrano z: Raw GraphQL Querying

GraphQL has all kinds of awesome tooling built around it. But like everything on the web, it ultimately comes down to data shootin’ across the ol’ network and responses coming back. If you need to talk to a GraphQL API endpoint, you don’t absolutely have to use some kind of framework or library to make requests against it. As a matter of fact, you can do it pretty cleanly in vanilla JavaScript.

Take the Pokémon API, available in GraphQL, which I found via this list of APIs. It has a GraphiQL interface for exploring.

From that page, you can execute queries and see the results. You can also poke into the Network tab in DevTools and see the payload for requests it sends off, and see that it’s just a bit of JSON that is POSTed.

We can make our own JSON in that format too! First, we’ll make it an object in the right format, utilizing template literals to make the GraphQL query look nice (which is actually required because the query syntax is dependent on white-space). Then we JSON-ify it with the native JavaScript API and POST it via the also-native fetch API.

See the Pen
Raw GraphQL
by Chris Coyier (@chriscoyier)
on CodePen.

Easy cheesy. And no fancy tooling to request exactly what you need, which is the core benefit of GraphQL.

The post Raw GraphQL Querying appeared first on CSS-Tricks.

Blue Beanie Day 2019

Post pobrano z: Blue Beanie Day 2019

November 30th, the official „Blue Beanie Day,” has come and gone. I’m not sure I ever grokked the exact spirit of it, but I’ve written about what it means to me. Last year:

Web standards, as an overall idea, has entirely taken hold and won the day. That’s worth celebrating, as the web would be kind of a joke without them. So now, our job is to uphold them. We need to cry foul when we see a browser go rogue and ship an API outside the standards process.

Building off that, I’d add the need to prevent browsers from breaking things that have worked for half a decade, like iOS 13 did with CSS parallax.

Zeldman, the Blue Beanie Day champion, isn’t particularly optimistic:

Mainly, though, Blue Beanie Day is receding from view because our industry as a whole thinks less and less about accessibility (not that we ever had an A game on the subject), and talks less and less about progressive enhancement, preferring to chase the ephemeral goal posts of over-engineered solutions to non-problems.

It’s people who won the browser wars, so I suppose it’s fitting that people are going to let it slip away.

The post Blue Beanie Day 2019 appeared first on CSS-Tricks.

Adam Argyle’s 2020 CSS Predictions

Post pobrano z: Adam Argyle’s 2020 CSS Predictions

I think Adam’s first prediction is his boldest, even beyond his Hail Mary prediction. CSS grid is awesome and gap is perhaps one of its best qualities, but gap superseding spacing things out in other ways (e.g. margin) is a bold prediction indeed, especially with Firefox being the only browser supporting it in flexbox.

Direct Link to Article — Permalink

The post Adam Argyle’s 2020 CSS Predictions appeared first on CSS-Tricks.

Yap

Post pobrano z: Yap

Interesting idea for a „chat room” from Postlight:

  1. Create a Yap chat room.
  2. Invite others to join and talk.
  3. Share a URL of just about anything.
  4. Everyone gathering can comment on what you’ve shared.
  5. If you think your conversation deserves an audience, share the URL of your chat publicly.
  6. Only six people can join. Lots of people can observe if you invite them. But just six chatters.

Yap.

Direct Link to Article — Permalink

The post Yap appeared first on CSS-Tricks.

Detecting Inactive Users

Post pobrano z: Detecting Inactive Users

Most of the time you don’t really care about whether a user is actively engaged or temporarily inactive on your application. Inactive, meaning, perhaps they got up to get a drink of water, or more likely, changed tabs to do something else for a bit. There are situations, though, when tracking the user activity and detecting inactive-ness might be handy.

Let’s think about few examples when you just might need that functionality:

  • tracking article reading time
  • auto saving form or document
  • auto pausing game
  • hiding video player controls
  • auto logging out users for security reasons

I recently encountered a feature that involved that last example, auto logging out inactive users for security reasons.

Why should we care about auto logout?

Many applications give users access to some amount of their personal data. Depending on the purpose of the application, the amount and the value of that data may be different. It may only be user’s name, but it may also be more sensitive data, like medical records, financial records, etc.

There are chances that some users may forget to log out and leave the session open. How many times has it happened to you? Maybe your phone suddenly rang, or you needed to leave immediately, leaving the browser on. Leaving a user session open is dangerous as someone else may use that session to extract sensitive data.

One way to fight this issue involves tracking if the user has interacted with the app within a certain period of time, then trigger logout if that time is exceeded. You may want to show a popover, or perhaps a timer that warns the user that logout is about to happen. Or you may just logout immediately when inactive user is detected.

Going one level down, what we want to do is count the time that’s passed from the user’s last interaction. If that time period is longer than our threshold, we want to fire our inactivity handler. If the user performs an action before the threshold is breached, we reset the counter and start counting again.

This article will show how we can implement such an activity tracking logic based on this example.

Step 1: Implement tracking logic

Let’s implement two functions. The first will be responsible for resetting our timer each time the user interacts with the app, and the second will handle situation when the user becomes inactive:

  • resetUserActivityTimeout – This will be our method that’s responsible for clearing the existing timeout and starting a new one each time the user interacts with the application.
  • inactiveUserAction – This will be our method that is fired when the user activity timeout runs out.
let userActivityTimeout = null;

function resetUserActivityTimeout() {
  clearTimeout(userActivityTimeout);
  userActivityTimeout = setTimeout(() => {
    inactiveUserAction();
  }, INACTIVE_USER_TIME_THRESHOLD);
}

function inactiveUserAction() {
  // logout logic
}

OK, so we have methods responsible for tracking the activity but we do not use them anywhere yet.

Step 2: Tracking activation

Now we need to implement methods that are responsible for activating the tracking. In those methods, we add event listeners that will call our resetUserActivityTimeout method when the event is detected. You can listen on as many events as you want, but for simplicity, we will restrict that list to a few of the most common ones.

function activateActivityTracker() {
  window.addEventListener("mousemove", resetUserActivityTimeout);
  window.addEventListener("scroll", resetUserActivityTimeout);
  window.addEventListener("keydown", resetUserActivityTimeout);
  window.addEventListener("resize", resetUserActivityTimeout);
}

That’s it. Our user tracking is ready. The only thing we need to do is to call the activateActivityTracker on our page load.

We can leave it like this, but if you look closer, there is a serious performance issue with the code we just committed. Each time the user interacts with the app, the whole logic runs. That’s good, but look closer. There are some types of events that are fired an enormous amount of times when the user interacts with the page, even if it isn’t necessary for our tracking. Let’s look at mousemove event. Even if you move your mouse just a touch, mousemove event will be fired dozens of times. This is a real performance killer. We can deal with that issue by introducing a throttler that will allow the user activity logic to be fired only once per specified time period.

Let’s do that now.

Step 3: Improve performance

First, we need to add one more variable that will keep reference to our throttler timeout.

let userActivityThrottlerTimeout = null

Then, we create a method that will create our throttler. In that method, we check if the throttler timeout already exists, and if it doesn’t, we create one that will fire the resetUserActivityTimeout after specific period of time. That is the period for which all user activity will not trigger the tracking logic again. After that time the throttler timeout is cleared allowing the next interaction to reset the activity tracker.

userActivityThrottler() {
  if (!userActivityThrottlerTimeout) {
    userActivityThrottlerTimeout = setTimeout(() => {
      resetUserActivityTimeout();

      clearTimeout(userActivityThrottlerTimeout);
      userActivityThrottlerTimeout = null;
    }, USER_ACTIVITY_THROTTLER_TIME);
  }
}

We just created a new method that should be fired on user interaction, so we need to remember to change the event handlers from resetUserActivityTimeout to userActivityThrottler in our activate logic.

activateActivityTracker() {
  window.addEventListener("mousemove", userActivityThrottler);
  // ...
}

Bonus: Let’s reVue it!

Now that we have our activity tracking logic implemented let’s see how can move that logic to an application build with Vue. We will base the explanation on this example.

First we need to move all variables into our component’s data, that is the place where all reactive props live.

export default {
  data() {
    return {
      isInactive: false,
      userActivityThrottlerTimeout: null,
      userActivityTimeout: null
    };
  },
// ...

Then we move all our functions to methods:

// ...
  methods: {
    activateActivityTracker() {...},
    resetUserActivityTimeout() {...},
    userActivityThrottler() {...},
    inactiveUserAction() {...}
  },
// ...

Since we are using Vue and it’s reactive system, we can drop all direct DOM manipulations i.(i.e. document.getElementById("app").innerHTML) and depend on our isInactive data property. We can access the data property directly in our component’s template like below.

<template>
  <div id="app">
    <p>User is inactive = {{ isInactive }}</p>
  </div>
</template>

Last thing we need to do is to find a proper place to activate the tracking logic. Vue comes with component lifecycle hooks which are exactly what we need — specifically the beforeMount hook. So let’s put it there.

// ...
  beforeMount() {
    this.activateActivityTracker();
  },
// ...

There is one more thing we can do. Since we are using timeouts and register event listeners on window, it is always a good practice to clean up a little bit after ourselves. We can do that in another lifecycle hook, beforeDestroy. Let’s remove all listeners that we registered and clear all timeouts when the component’s lifecycle comes to an end.

// ...
  beforeDestroy() {
    window.removeEventListener("mousemove", this.userActivityThrottler);
    window.removeEventListener("scroll", this.userActivityThrottler);
    window.removeEventListener("keydown", this.userActivityThrottler);
    window.removeEventListener("resize", this.userActivityThrottler);
  
    clearTimeout(this.userActivityTimeout);
    clearTimeout(this.userActivityThrottlerTimeout);
  }
// ...

That’s a wrap!

This example concentrates purely on detecting user interaction with the application, reacting to it and firing a method when no interaction is detected within specific period of time. I wanted this example to be as universal as possible, so that’s why I leave the implementation of what should happened when an inactive user it detected to you.

I hope you will find this solution useful in your project!

The post Detecting Inactive Users appeared first on CSS-Tricks.

How Facebook Avoids Ad Blockers

Post pobrano z: How Facebook Avoids Ad Blockers

Dylan Paulus:

Facebook actually hides 'dummy’ DOM nodes between the 'Sponsored’ text. These values are entirely random characters, with a random number of DOM nodes between them. Invisible characters. At this point our CSS ad blocker is completely broken. There is no way for us to possibly code every possible value in CSS.

We’ve covered this before when Mike Pan noted it. Looks like it’s evolved a bit since then, getting even a little tricker.

I just opened my Facebook and selected „Copy Outer HTML” on the word „Sponsored”:

<span class="v_19dt4zixpg r_19dt4zk7i5"><span class="fsm fwn fcg"><span class="q_19dt4zirbc"><a class="d_19dt4zioka h_19dt4ziol1" role="button" id="u_fetchstream_3_6"><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="a" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="t" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="S" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="p" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="r" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="i" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="n" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="S" class="s_19dt4ziok9 l_19dt4zlqyi n_19dt4ziokm"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="i" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="p" class="s_19dt4ziok9 l_19dt4zlqyi n_19dt4ziokm"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="o" class="s_19dt4ziok9 l_19dt4zlqyi n_19dt4ziokm"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="i" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="n" class="s_19dt4ziok9 l_19dt4zlqyi n_19dt4ziokm"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="o" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="a" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="c" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="s" class="s_19dt4ziok9 l_19dt4zlqyi n_19dt4ziokm"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="n" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="s" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="o" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="r" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="e" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="o" class="s_19dt4ziok9 l_19dt4zlqyi n_19dt4ziokm"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="g" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="r" class="s_19dt4ziok9 l_19dt4zlqyi n_19dt4ziokm"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="d" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="e" class="s_19dt4ziok9 l_19dt4zlqyi n_19dt4ziokm"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="f" class="s_19dt4ziok9 l_19dt4zlqyi b_19dt4ziokl"></span></span><span class="s_19dt4ziok9 d_19dt4ziok- e_19dt4ziokq"><span data-content="d" class="s_19dt4ziok9 l_19dt4zlqyi n_19dt4ziokm"></span></span></span></a></span></span></span>

I guess we shouldn’t be terribly surprised at Facebook being user-hostile. I can imagine a workplace environment where fighting against ad blockers is turned into this fun kinda cat-and-mouse technological tennis match. But what they are fighting against is people wanting to exert a little control over what they allow into their eyes, ears, and brains.

It’s worth noting that nothing else in the DOM helps identify a post as an ad. So in that sense it’s just like how Google has evolved SERPs in how ads look just like organic results aside from a tiny „AD” before the URL.

We run sponsored posts here on CSS-Tricks too, so please feel free to hold our feet to the fire of accountability if you feel sponsored posts aren’t clear enough.

Direct Link to Article — Permalink

The post How Facebook Avoids Ad Blockers appeared first on CSS-Tricks.

Making a Better Custom Select Element

Post pobrano z: Making a Better Custom Select Element

We just covered The Current State of Styling Selects in 2019, but we didn’t get nearly as far and fancy as Julie Grundy gets here. There is a decent chunk of JavaScript that powers it, so I’m still very much eyeballing browsers’ recent interest in giving us more powerful selects in (presumably) just HTML and CSS.

I tossed a fork on CodePen in case you just wanna see the final result.

This is also the first article in the 2019 edition of 24 Ways, the long-running and wonderful annual advent calendar for developers that is worth reading every single year.

Direct Link to Article — Permalink

The post Making a Better Custom Select Element appeared first on CSS-Tricks.

WordPress.com: One CMS, Infinite Possibilities

Post pobrano z: WordPress.com: One CMS, Infinite Possibilities

(This is a sponsored post.)

Have you ever looked at a site and knew exactly what CMS powers it? You might see a distinctive design aesthetic that gives it away. Or maybe it’s something even less obvious and even harder to articulate, but you know it when you see it.

That seems true with just about any platform, especially those that rely on a set of templates. If you were to jump from one site ot another on the same platform, you can see the similarities, sort of like walking down the street of a neighborhood where all the homes are designed by the same architect.

It’s not a bad thing. But like homes, we tend to want websites with personality and that feel unique. That’s one of the things that makes WordPress.com a nice hosted platform option.

Yes, it has core themes, some of which are commonly used. What it also has is hundreds of others, including 110 themes that are free. The designs range from portfolio- and business-themed sites to ones themed around traditional blogs, weddings, travel, music, and food. There’s so many to choose from, and they’re introducing more every year. Take a look through some live sites using WordPress.com. The variety is awesome and showcases the many possibilities of WordPress as a content management system.

We’ve said it before: if you can build a site with WordPress.com, you should build a site on WordPress.com. We’re proud to have WordPress as a sponsor here at CSS-Tricks and wouldn’t hesitate to recommend it to anyone who needs a quick and easy way to spin up a site. Plus, with a free plan tier, it’s even easier to get started.

Start your website

Direct Link to Article — Permalink

The post WordPress.com: One CMS, Infinite Possibilities appeared first on CSS-Tricks.

Quoting in HTML: Quotations, Citations, and Blockquotes

Post pobrano z: Quoting in HTML: Quotations, Citations, and Blockquotes

It’s all too common to see the incorrect HTML used for quotes in markup. In this article, let’s dig into all this, looking at different situations and different HTML tags to handle those situations.

There are three major HTML elements involved in quotations:

  • <blockquote>
  • <q>
  • <cite>

Let’s take a look.

Blockquotes

Blockquote tags are used for distinguishing quoted text from the rest of the content. My tenth grade English teacher drilled it into my head that any quote of four lines or longer should be set apart this way. The HTML spec has no such requirement, but as long as the text is a quote and you want it to be set apart from the surrounding text and tags, a blockquote is the semantic choice.

By default, browsers indent blockquotes by adding margin on each side.

See the Pen
The Blockquote Tag
by Undead Institute (@undeadinstitute)
on CodePen.

As a flow element (i.e. “block level” element), blockquote can contain other elements inside it. For example, we can drop paragraphs in there with no problem:

<blockquote>
  <p></p>
  <p></p>
</blockquote>

But it could be other elements, too, like a heading or an unordered list:

<blockquote>
    <h2></h2>
    <ul>
      <li></li>
      <li></li>
    </ul>
</blockquote>

It’s important to note that blockquotes should only be used for quotations rather than as a decorative element in a design. This also aids accessibility as screen reader users can jump between blockquotes. Thus a blockquote element used solely for aesthetics could really confuse those users. If you need something more decorative that falls outside the bounds of extended quotations, then perhaps a div with a class is the way to go.

blockquote,
.callout-block {
  /* These could share styling */
}

Quoting with Q

Q tags (<q>) are for inline quotes, or what my tenth grade teacher would say are those under four lines. Many modern browsers will automatically add quotation marks to the quote as pseudo elements but you may need a backup solution for older browsers.

See the Pen
The Q Tag
by CSS-Tricks (@css-tricks)
on CodePen.

Typical quotation marks are just as valid for inline quotes as the <q> element. The benefits of using <q>, however, are that it includes a cite attribute, automatic handling of quotation marks, and automatic handling of quote levels. <q> elements should not used for sarcasm (e.g. “you would use a <q> tag for sarcasm, wouldn’t you?”), or signifying a word with air quotes (e.g. “awesome” is an “accurate” description of the author). But if you can figure out how to mark up air quotes, please let me know. Because that would be “awesome.”

The citation attribute

Both <q> and blockquotes can use a citation (cite) attribute. This attribute holds a URL that provides context and/or a reference for the quoted material. The spec makes a point of saying that the URL can be surrounded by spaces. (I’m not sure why that’s pointed out, but if you want to anger the semantic code deities, you’ll have to do more than throw spaces around.)

<p>The officer left a note saying <q cite="https://johnrhea.com/summons">You have been summoned to appear on the 4th day of January on charges of attempted reader bribery.</q></p>

That cite attribute isn’t visible to the user by default. You could add it in with a sprinkle of CSS magic like the following demo. You could even fiddle with it further to make the citation appear on hover.

See the Pen
Attributable citations
by CSS-Tricks (@css-tricks)
on CodePen.

Neither of those options are particularly great. If you need to cite a source such that users can see it and go to it, you should do it in HTML and probably with the <cite> element, which we’ll cover next.

The citation element

The <cite> tag should be used for referencing creative work rather than the person who said or wrote the quote. In other words, it’s not for quotes. Here are the examples from the spec:

<p>My favorite book is <cite>The Reality Dysfunction</cite> by
Peter F. Hamilton. My favorite comic is <cite>Pearls Before
Swine</cite> by Stephan Pastis. My favorite track is <cite>Jive
Samba</cite> by the Cannonball Adderley Sextet.</p>

Here’s another example:

See the Pen
Cite This!
by CSS-Tricks (@css-tricks)
on CodePen.

If the author of this article told you he’d give you a cupcake, and you <cite> him by name, that would be semantically incorrect. Thus no cupcakes would change hands. If you cited the article in which he offered you a cupcake, that would be semantically correct, but since the author wouldn’t do that, you still wouldn’t get a cupcake. Sorry.

By default, browsers italicize cite tags and there’s no requirement that a <q> or <blockquote> be present to use the cite element. If you want to cite a book or other creative work, then slap it in the cite element. The semantic deities will smile on you for not using either <i> or <em> elements.

But where to put the cite element? Inside? Outside? The upside down? If we put it inside the <blockquote> or the <q>, we’re making it part of the quote. That’s forbidden by the spec for just that reason.

<!-- This is apparently wrong -->
<blockquote>
  Quote about cupcake distribution from an article
  <cite>The Article</cite>
</blockquote>

Putting it outside just feels wrong and also requires you to have an enclosing element like a <div> if you wanted to style them together.

<div class="need-to-style-together">
  <blockquote>
    Quote about cupcake distribution from an article
  </blockquote>
  <cite>The Article</cite>
</div>

N.B. If you google this issue you may come across an HTML5 Doctor article from 2013 that contradicts much of what’s laid out here. That said, every time it links to the docs for support, the docs agree with the article you’re currently reading rather than the HTML5 Doctor article. Most likely the docs have changed since that article was written.

Hey, what about the figure element?

One way to mark up a quotation — and in a way that pleases the semantic code deities — is to put the blockquote within a figure element. Then, put the cite element and any other author or citation information in a figcaption.

<figure class="quote">
  <blockquote>
    But web browsers aren’t like web servers. If your back-end code is getting so big that it’s starting to run noticably slowly, you can throw more computing power at it by scaling up your server. That’s not an option on the front-end where you don’t really have one run-time environment—your end users have their own run-time environment with its own constraints around computing power and network connectivity.
  </blockquote>
  <figcaption>
    &mdash; Jeremy Keith, <cite>Mental models</cite>
  </figcaption>
</figure>

While this doubles the number of elements needed, there are several benefits:

  1. It’s semantically correct for all four elements.
  2. It allows you to both include and encapsulate author information beyond citing the name of the work.
  3. It gives you an easy way to style the quote without resorting to divs, spans or wretchedness.

See the Pen
It Figures You’d Say That
by CSS-Tricks (@css-tricks)
on CodePen.

None of this is for dialogue

Not <dialog>! Those are for attention-grabbing modals. Dialogue, as in, conversational exchanges between people speaking or typing to each other.

Neither <blockquote> nor <q> nor <cite> are to be used for dialogue and similar exchanges between speakers. If you’re marking up dialogue, you can use whatever makes the most sense to you. There’s no semantic way to do it. That said, the spec suggests <p> tags and punctuation with <span> or <b> tags to designate the speaker and <i> tags to mark stage directions.

Accessibility of quotes

From the research I’ve done, screen readers should not have any issue with understanding semantic-deity-approved <q>, <blockquote>, or <cite> tags.

More “ways” to “quote”

You can add quotation marks to a <blockquote> using CSS pseudo elements. The <q> element comes with quotation marks baked in so they need not be added, however adding them as pseudo-elements can be a workaround for older browsers that don’t automatically add them. Since this is how modern browsers add the quotation marks there’s no danger of adding duplicate quotes. New browsers will overwrite the default pseudo elements, and older browsers that support pseudo elements will add the quotes.

But you can’t, like I did, assume that the above will always give you smart opening and closing quotes. Even if the font supports smart quotes, sometimes straight quotes will be displayed. To be safe, it’s better to use the quotes CSS property to up the intelligence on those quotation marks.

blockquote {
  quotes: "“" "”" "‘" "’";
}

See the Pen
"Quot-a-tizing" the blockquote
by CSS-Tricks (@css-tricks)
on CodePen.

Multi-level quoting

Now let’s look at quote levels. The <q> tag will automatically adjust quote levels.

Let’s say you’re in an area that uses the British convention of using single quotes. You could use the CSS quotes rule to put the opening and closing single quotes first in the list. Here’s an example of both ways:

See the Pen
Quote Within a Quote
by CSS-Tricks (@css-tricks)
on CodePen.

There is no limit to nesting. Those nested <q> elements could even be within a blockquote that’s within a blockquote.

If you add quotation marks to a blockquote, know that the blockquote does not change the quote level the way a <q> tag does. If you expect to have quotes within a blockquote, you may want to add a descendant selector rule to start <q> elements within a blockquote at the single quote level (or double quotes if you follow British conventions).

 blockquote q {
  quotes: "‘" "’" "“" "”";
}

The last quote level you put in will continue through subsequent levels of quotation. To use the double, single, double, single… convention, add more levels to the CSS quotes property.

q {
  quotes: "“" "”" "‘" "’" "“" "”" "‘" "’" "“" "”";
}

Hanging punctuation

Many typography experts will tell you that hanging the quotation marks on blockquotes looks better (and they’re right). Hanging punctuation is, in this case, quotation marks that are pushed out from the text so that the characters of the text line up vertically.

One possibility in CSS is using a slightly negative value on the text-indent property. The exact negative indentation will vary by font, so be sure to double check the spacing with the font you end up using.

blockquote {
  text-indent: -0.45em;
}

There is a nicer way to handle this by using the hanging-punctuation CSS property. It’s only supported in Safari at the time of this writing, so we’ll have to progressively enhance:

/* Fallback */
blockquote {
  text-indent: -0.45em;
}

/* If there's support, erase the indent and use the property instead */
@supports ( hanging-punctuation: first) {
  blockquote {
    text-indent: 0;
    hanging-punctuation: first;
  }
}

Using hanging-punctuation is better because it’s less fiddly. It’ll just work when it can.

See the Pen
Hanging Your Punctuation
by CSS-Tricks (@css-tricks)
on CodePen.

Can we animate quotation marks?

Of course we can.

See the Pen
Dancing Quotes
by CSS-Tricks (@css-tricks)
on CodePen.

Why you’d need to do this, I’m not totally sure, but the quotation marks in a <q> tag are added are pseudo elements in the UA stylesheet, so we’re able to select and style them — including animation — if we need to.

Wait, maybe we just solved the air quotes thing after all.

The post Quoting in HTML: Quotations, Citations, and Blockquotes appeared first on CSS-Tricks.