Back to Top

Expert advice. Actionable tactics. Lowest rates expire Saturday!

Join us for 55+ sessions led by 60+ real-world marketers and the solutions you need to overcome specific marketing challenges.

Please visit Marketing Land for the full article.

Reblogged 6 days ago from feeds.marketingland.com

Most consumers believe online privacy is impossible, survey finds

The poll of U.S. and U.K. consumers also found that people are changing their behavior and sharing less information online.

Please visit Marketing Land for the full article.

Reblogged 6 days ago from feeds.marketingland.com

The need for speed in search: 5 speed types to master now

To be competitive in search, you must audit and optimize desktop and mobile page speeds while also making data ready for real-time personalization.

Please visit Search Engine Land for the full article.

Reblogged 6 days ago from feeds.searchengineland.com

How To Build A Sketch Plugin With JavaScript, HTML And CSS (Part 2)

How To Build A Sketch Plugin With JavaScript, HTML And CSS (Part 2)

How To Build A Sketch Plugin With JavaScript, HTML And CSS (Part 2)

Matt Curtis

2019-07-08T12:30:59+02:00
2019-07-10T11:35:59+00:00

As mentioned in part 1, this tutorial is intended for people who know and use the Sketch app and are not afraid of dabbling with code as well. To profit from it the most, you will need to have at least some basic experience writing JavaScript (and, optionally, HTML/CSS).

In the previous part of this tutorial, we learned about the basic files that make up a plugin, and how to create the plugin’s user interface. In this second and final part, we’ll learn how to connect the user interface to the core plugin code and how to implement the plugin’s main features. Last but not least, we’ll also learn how to optimize the code and the way the plugin works.

Building The Plugin’s User Interface: Making Our Web Interface And The Sketch Plugin Code “Talk” To Each Other

The next thing we need to do is to set up communication between our web interface and the Sketch plugin.

We need to be able to send a message from our web interface to the Sketch plugin when the “Apply” button in our web interface is clicked. This message needs to tell us about what settings the user has input — like the number of steps, rotation amount, the number of duplicates to create, and so on.

WKWebView makes this task a little bit easier for us: we can send messages to our Sketch plugin from our web interface’s JavaScript code by using the window.webkit.messageHandlers API.

On our Sketch code’s side, we can use another method, addScriptMessageHandler:name: (or addScriptMessageHandler_name) to register a message handler that will be called whenever it receives a message sent from our plugin web interface.

Let’s start by making sure we can receive messages from our web UI. Head over to our ui.js file’s createWebView function, and add the following:

function createWebView(pageURL){
        const webView = WKWebView.alloc().init();

        //        Set handler for messages from script

        const userContentController = webView.configuration().userContentController();
        
        const ourMessageHandler = ...

        userContentController.addScriptMessageHandler_name(
                ourMessageHandler, "sketchPlugin"
        );

        //        Load page into web view

        webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent());

        return webView;
};

Here we use the web view’s userContentController property to add a message handler we’ve named “sketchPlugin”. This “user content controller” is the bridge that ensures messages get across from our web view.

You might have noticed something odd about the above code: the object we’re adding as the message handler, ourMessageHandler, doesn’t exist yet! Unfortunately, we can’t just use a regular JavaScript object or function as the handler, as this method expects a certain kind of native object.

Luckily for us, we can get around this limitation by using MochaJSDelegate, a mini-library I wrote that makes it possible to create the kind of native object we need using regular ol’ JavaScript. You’ll need to manually download and save it in your plugin bundle under Sketch/MochaJSDelegate.js.

In order to use it, we’ll need to first import it into ui.js. Add the following at the top of the file:

const MochaJSDelegate = require("./MochaJSDelegate");

Now we can use MochaJSDelegate to create the type of message handler addScriptMessageHandler:name: is expecting:

function createWebView(pageURL){
        const webView = WKWebView.alloc().init();

        //        Set handler for messages from script

        const userContentController = webView.configuration().userContentController();

        const scriptMessageHandler = new MochaJSDelegate({
                "userContentController:didReceiveScriptMessage:": (_, wkMessage) => {
                        /* handle message here */
                }
        }).getClassInstance();

        userContentController.addScriptMessageHandler_name(
                scriptMessageHandler, "sketchPlugin"
        );

        //        Load page into web view

        webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent());

        return webView;
};

The code we just added creates the native object we need. It also defines a method on that object named userContentController:didReceiveScriptMessage: — this method is then called with the message we want as the second argument. Since we’re not actually sending any messages yet, we’ll have to come back here at a later time and add some code to actually parse and handle the messages we receive.

Next, we need to add some code to our web interface to send us those messages. Head over to /Resources/web-ui/script.js. You’ll find I’ve already written most of the code that handles retrieving the values of the HTML <inputs /> the user will enter their options into.

What’s still left for us to do is to add the code that actually sends the values over to our Sketch code:

Find the apply function and add the following to the end of it:

//        Send user inputs to sketch plugin

window.webkit.messageHandlers.sketchPlugin.postMessage(JSON.stringify({
        stepCount, startingOptions, stepOptions
}));

Here we use window.webkit.messageHandlers API we mentioned earlier to access the message handler we registered above as sketchPlugin. Then send a message to it with a JSON string containing the user’s inputs.

Let’s make sure everything is set up properly. Head back to /Sketch/ui.js. In order to make sure we’re getting messages as we expect, we’ll modify the method we defined earlier so that it displays a dialog when we get a message:

function createWebView(pageURL){
        // ...

        const scriptMessageHandler = new MochaJSDelegate({
                "userContentController:didReceiveScriptMessage:": (_, wkMessage) => {
                        const UI = require("sketch/ui");
                        
                        UI.alert("Hey, a message!", wkMessage.body());
                }
        }).getClassInstance();

        userContentController.addScriptMessageHandler_name(
                scriptMessageHandler, "sketchPlugin"
        );

        // ...
};

Now run the plugin (you may need to first close any existing Mosaic window you have opened), enter some values, then click “Apply”. You should see an alert like the one below — this means everything is wired up correctly and our message went through successfully! If not, go back over the previous steps and ensure that everything was done as described.

The dialog you should see appear once you click Apply. (Large preview)

Now that we’re able to send messages from our interface to our plugin, we can move on to writing the code that actually does something useful with that information: generating our layer mosaics.

Generating The Layer Mosaics

Let’s take stock of what’s necessary in order to make this happen. Simplifying things a bit, what our code needs to do is:

  1. Find the current document.
  2. Find the current document’s selected layer.
  3. Duplicate the selected layer (we’ll call it the template layer) x number of times.
  4. For each duplicate, tweak its position, rotation, opacity, etc., by the specific values (amounts) set by the user.

Now that we’ve got a reasonable plan, let’s continue writing. Sticking with our pattern of modularizing our code, let’s create a new file, mosaic.js in the Sketch/ folder, and add to it the following code:

function mosaic(options){

};

module.export = mosaic;

We’ll use this function as the only export of this module since it makes for a simpler API to use once we import it — we can just call mosaic() with whatever options we get from the web interface.

The first two steps we need to take are getting the current document, and then its selected layer. The Sketch API has a built-in library for document manipulation which we can get access to by importing the sketch/dom module. We only need the Document object right now, so we’ll pull it out explicitly. At the top of the file, add:

const { Document } = require("sketch/dom");

The Document object has a method specifically for accessing the current document we can use, called getSelectedDocument(). Once we have the current document instance, we can access whatever layers the user has selected via the document’s selectedLayers property. In our case, though, we only care about single-layer selections, so we’ll only grab the first layer the user has selected:

function mosaic(options){
        const document = Document.getSelectedDocument();
        const selectedLayer = document.selectedLayers.layers[0];
};

module.export = mosaic;

Note: You might have been expecting selectedLayers itself to be an array, but it’s not. Instead, it’s an instance of the Selection class. There’s a reason for this: the Selection class contains a bunch of useful helper methods for manipulating the selection like clear, map, reduce, and forEach. It exposes the actual layer array via the layer property.

Let’s also add some warning feedback in case the user forgets to open a document or to select something:

const UI = require("sketch/ui");

function mosaic(options){
        const document = Document.getSelectedDocument();

        //        Safety check:

        if(!document){
                UI.alert("Mosaic", "⚠️ Please select/focus a document.");

                return;
        }

        //        Safety check:

        const selectedLayer = document.selectedLayers.layers[0];

        if(!selectedLayer){
                UI.alert("Mosaic", "⚠️ Please select a layer to duplicate.");
                
                return;
        }
};

module.export = mosaic;

Now that we’ve written the code for steps 1 and 2 (finding the current document and selected layer), we need to address steps 3 and 4:

  • Duplicate the template layer x number of times.
  • For each duplicate, tweak its position, rotation, opacity, etc., by the specific values set by the user.

Let’s start by pulling all the relevant information we need out of options: the number of times to duplicate, starting options, and step options. We can once again use destructuring (like we did earlier with Document) to pull those properties out of options:

function mosaic(options) {
        //        ...
        
        //        Destructure options:

        var { stepCount, startingOptions, stepOptions } = options;
}

Next, let’s sanitize our inputs and ensure that step count is always at least 1:

function mosaic(options) {
        //        ...
        
        //        Destructure options:
        
        var { stepCount, startingOptions, stepOptions } = options;
        
        stepCount = Math.max(1, stepCount);
}

Now we need to make sure that the template layer’s opacity, rotation, etc., all match up with the user’s desired starting values. Since applying the user’s options to a layer is going to be something we’ll do a lot of, we’ll move this work into its own method:

function configureLayer(layer, options, shouldAdjustSpacing){
        const { opacity, rotation, direction, spacing } = options;

        layer.style.opacity = opacity / 100;
        layer.transform.rotation = rotation;

        if(shouldAdjustSpacing){
                const directionAsRadians = direction * (Math.PI / 180);
                const vector = {
                        x: Math.cos(directionAsRadians),
                        y: Math.sin(directionAsRadians)
                };

                layer.frame.x += vector.x * spacing;
                layer.frame.y += vector.y * spacing;
        }
};

And because spacing only needs to be applied in-between the duplicates and not the template layer, we’ve added a specific flag, shouldAdjustSpacing, that we can set to true or false depending on whether we’re applying options to a template layer or not. That way we can ensure that rotation and opacity will be applied to the template, but not spacing.

Back in the mosaic method, let’s now ensure that the starting options are applied to the template layer:

function mosaic(options){
        //        ...
        
        //        Configure template layer

        var layer = group.layers[0];
        
        configureLayer(layer, startingOptions, false);
}

Next, we need to create our duplicates. First, let’s create a variable that we can use to track what the options for the current duplicate are:

function mosaic(options){
        //        ...

        var currentOptions; // ...
}

Since we already applied the starting options to the template layer, we need to take those options we just applied and add the relative values of stepOptions in order to get the options to apply to the next layer. Since we’ll also be doing this several more times in our loop, we’ll also move this work into a specific method, stepOptionsBy:

function stepOptionsBy(start, step){
        const newOptions = {};
        
        for(let key in start){
                newOptions[key] = start[key] + step[key];
        }

        return newOptions;
};

After that, we need to write a loop that duplicates the previous layer, applies the current options to it, then offsets (or “steps”) the current options in order to get the options for the next duplicate:

function mosaic(options) {
        //        ...
        
        var currentOptions = stepOptionsBy(startingOptions, stepOptions);

        for(let i = 0; i < (stepCount - 1); i++){
                let duplicateLayer = layer.duplicate();

                configureLayer(duplicateLayer, currentOptions, true);

                currentOptions = stepOptionsBy(currentOptions, stepOptions);
                layer = duplicateLayer;
        }
}

All done — we’ve successfully written the core of what our plugin is supposed to do! Now, we need to wire things up so that when the user actually clicks the “Apply” button our mosaic code is invoked.

Let’s head back to ui.js and adjust our message handling code. What we’ll need to do is parse the JSON string of options we’re getting so that they’re turned into an object we can actually use. Once we have these options, we can then call the mosaic function with them.

First, parsing. We’ll need to update our message handling function to parse the JSON message we get:

function createWebView(pageURL){
        //        ...
        
        const scriptMessageHandler = new MochaJSDelegate({
                "userContentController:didReceiveScriptMessage:": (_, wkMessage) => {
                        const message = JSON.parse(wkMessage.body());
                }
        });
}

Next, we’ll need to pass this over to our mosaic function. However, this isn’t really something our code in ui.js should be doing — it’s supposed to be primarily concerned with what’s necessary to display interface-related things on screen — not creating mosaics itself. To keep these responsibilities separate, we’ll add a second argument to createWebView that takes a function, and we’ll call that function whenever we receive options from the web interface.

Let’s name this argument onApplyMessage:

function createWebView(pageURL, onApplyMessage){
        // ...
        
        const scriptMessageHandler = new MochaJSDelegate({
                "userContentController:didReceiveScriptMessage:": (_, wkMessage) => {
                        const message = JSON.parse(wkMessage.body());
                        
                        onApplyMessage(message);
                }
        });
}

We’ll also need to modify our exported method, loadAndShow, to take this onApplyMessage argument as well and pass it off to createWebView:

function loadAndShow(baseURL, onApplyMessage){
        //        ...
        
        const webView = createWebView(pageURL, onApplyMessage);
}

Finally, head over to main.js. We now need to import our mosaic function, and call it with the options we receive from the plugin’s user interface:

const mosaic = require("./mosaic");

function onRun(context){
        UI.loadAndShow(context.scriptURL, options => {
                mosaic(options);
        });
};

We’re almost done!

However, if we ran our code now and clicked the “Apply” button in the plugin interface, nothing would happen. Why? The reason is due to how Sketch scripts are run: by default, they “live” only until the bottom of your script is reached, after which Sketch destroys it and frees up whatever resources it was using.

This is a problem for us since it means that anything we need to have asynchronously happen (in this case, that’s after the bottom of our code is reached), like receiving messages, cannot, because our script has been destroyed. This means we wouldn’t get any of our messages from the web interface since we’re not around to receive and respond to them!

There’s a way to signal to Sketch that we need our script to stay alive beyond this point, using Fibers. By creating a Fiber, we tell Sketch that something asynchronous is happening and that it needs to keep our script around. Sketch will then only destroy our script when absolutely necessary (like the user closing Sketch, or when the Mosaic plugin needs to be updated):

//        ...

const Async = require("sketch/async");

var fiber;

function onRun(context){
    if(!fiber){
        fiber = Async.createFiber();
        fiber.onCleanup(() => {
            UI.cleanup();
        });
    }
    
    UI.loadAndShow(context.scriptURL, options => {
        mosaic(options);
    });
};

Voilà! Let’s try out our plugin now. With a layer selected in Sketch, enter some settings, then click apply:

Let’s try out our plugin now — with a layer selected in Sketch, enter some settings, then click “Apply.”

Final Improvements

Now that we’ve got the majority of our plugin’s functionality implemented, we can try to “zoom out” a bit and take a look at the big picture.

Improving The User’s Experience

If you’ve played around with the plugin in its current state, you might’ve noticed that one of the biggest points of friction appears when you try to edit a Mosaic. Once you create one, you have to hit undo, adjust the options, then click ‘Apply’ (or press Enter). It also makes it harder to edit a Mosaic after you’ve left your document and returned to it later, since your undo/redo history will have been wiped out, leaving you to manually delete the duplicate layers yourself.

In a more ideal flow, the user could just select a Mosaic group, adjust options and watch the Mosaic update until they get the exact arrangement they’re looking for. To implement this, we have two problems to solve:

  1. First, we’ll need a way to group the duplicates that make up a Mosaic together. Sketch provides the concept of Groups, which we can use to solve this problem.
  2. Second, we’ll need a way to tell the difference between a normal, user-created group and a Mosaic group. Sketch’s API also gives us a way to store information on any given layer, which we can use as a way tag and later identify a group as one of our ‘special’ Mosaic groups.

Let’s revisit the logic we wrote in the previous section to address this. Our original code follows the following steps:

  1. Find the current document.
  2. Find the current document’s selected layer.
  3. Duplicate the selected layer (we’ll call it the template layer) x number of times.
  4. For each duplicate, tweak its position, rotation, opacity, etc., by the specific values (amounts) set by the user.

In order to make our new user flow possible, we need to change these steps to:

  1. Grab the current document.
  2. Grab the current document’s selected layer.
  3. Determine whether the selected layer is a Mosaic group or not.
    • If it’s some other layer, use it as the template layer and go to step 4.
    • If it is a Mosaic group, consider the first layer in it as the template layer, and go to step 5.
  4. Wrap the template layer inside a group, and mark that group as a Mosaic group.
  5. Remove all layers from inside the group except the template layer.
  6. Duplicate the template layer x number of times.
  7. For each duplicate, tweak its position, rotation, opacity, etc., by the specific values set by the user.

We’ve got three new steps. For the first new step, step 3, we’ll create a function named findOrMakeSpecialGroupIfNeeded that will look at the layer passed to it to determine whether or not it’s a Mosaic group. If it is, we’ll just return it. Since the user could potentially select a sublayer nested deep in a Mosaic group, we’ll also need to check the parents of the selected layer to tell if they’re one of our Mosaic groups as well:

function findOrMakeSpecialGroupIfNeeded(layer){
        //        Loop up through the parent hierarchy, looking for a special group

        var layerToCheck = layer;

        while(layerToCheck){
                if(/* TODO: is mosaic layer? */){
                        return layerToCheck;
                }

                layerToCheck = layerToCheck.parent;
        }
};

If we weren’t able to find a Mosaic group we’ll simply wrap the layer we were passed inside a Group, then tag it as a Mosaic group.

Back at the top of the file, we’ll need to pull out the Group class now too:

const { Document, Group } = require("sketch/dom");
function findOrMakeSpecialGroupIfNeeded(layer){
        //        Loop up through the parent hierarchy, looking for a special group

        var layerToCheck = layer;

        while(layerToCheck){
                if(/* TODO: is mosaic layer? */){
                        return layerToCheck;
                }

                layerToCheck = layerToCheck.parent;
        }
        
        //        Group

        const destinationParent = layer.parent;
        const group = new Group({
                name: "Mosaic Group",
                layers: [ layer ],
                parent: destinationParent
        });
        
        /* TODO: mark group as mosaic layer */
        
        return group;
};

Now we need to fill in the gaps (todo’s). To begin with, we need a means of identifying whether or not a group is one of the special groups belonging to us or not. Here, the Settings module of the Sketch library comes to our rescue. We can use it to store custom information on a particular layer, and also to read it back.

Once we import the module at the top of the file:

const Settings = require("sketch/settings");

We can then use two key methods it provides, setLayerSettingForKey and layerSettingForKey, to set and read data off a layer:

function findOrMakeSpecialGroupIfNeeded(layer){
        const isSpecialGroupKey = "is-mosaic-group";

        //        Loop up through the parent hierarchy, looking for a special group

        var layerToCheck = layer;

        while(layerToCheck){
                let isSpecialGroup = Settings.layerSettingForKey(layerToCheck, isSpecialGroupKey);

                if(isSpecialGroup) return layerToCheck;

                layerToCheck = layerToCheck.parent;
        }
        
        //        Group

        const destinationParent = layer.parent;

       layer.remove(); // explicitly remove layer from it’s existing parent before adding it to group

        const group = new Group({
                name: "Mosaic Group",
                layers: [ layer ],
                parent: destinationParent
        });
        
        Settings.setLayerSettingForKey(group, isSpecialGroupKey, true);

        return group;
};

Now that we’ve got a method that handles wrapping a layer in a mosaic group (or, if already a mosaic group, just returns it) we can now plug it into our main mosaic method just after our safety checks:

function mosaic(options){
        //       ... safety checks ...

        //        Group selection if needed:

        const group = findOrMakeSpecialGroupIfNeeded(selectedLayer);
}

Next we’ll add a loop to remove all layers from the group except the template layer (which is the first):

function mosaic(options) {
        //        ...
        
        //        Remove all layers except the first:
        
        while(group.layers.length > 1){
                group.layers[group.layers.length - 1].remove();
        }
}

Lastly, we’ll make sure that the group’s size is fitted to its new contents since the user might have originally selected a layer nested within the old group (a layer that we might have removed).

We’ll also need to make sure to set the current selection to our mosaic group itself. This will ensure that if the user is making a bunch of rapid changes to the same mosaic group it won’t become deselected. After the code we already wrote to duplicate a layer, add:

function mosaic(options) {
        //        ...
        
        //        Fit group to duplicates

        group.adjustToFit();

        //        Set selection to the group

        document.selectedLayers.clear();
        group.selected = true;
}

Try out the plugin again. You should find that editing a mosaic is much smoother now!

Improving The Interface

One other thing you might notice is the lack of synchronization between the display window and the interface inside it, in terms of them both becoming visible at the same time. This is due to the fact that when we display the window, the web interface isn’t guaranteed to have finished loading, so sometimes it’ll “pop” or “flash in” afterwards.

One way to fix this is by listening for when the web interface has finished loading, and only then show our window. There is a method, webView:didFinishNavigation:, that WKWebView will call when the current page has finished loading. We can use it to get exactly the notification we’re looking for.

Back in ui.js, we’ll extend the MochaJSDelegate instance we created to implement this method, which will in turn call the onLoadFinish argument we’ll pass to createWebView:

function createWebView(pageURL, onApplyMessage, onLoadFinish){
        const webView = WKWebView.alloc().init();

        //        Create delegate

        const delegate = new MochaJSDelegate({
                "webView:didFinishNavigation:": (webView, navigation) => {
                        onLoadFinish();
                },
                "userContentController:didReceiveScriptMessage:": (_, wkMessage) => {
                        const message = JSON.parse(wkMessage.body());
                        
                        onApplyMessage(message);
                }
        }).getClassInstance();

        //        Set load complete handler

        webView.navigationDelegate = delegate;

        //        Set handler for messages from script

        const userContentController = webView.configuration().userContentController();

        userContentController.addScriptMessageHandler_name(delegate, "sketchPlugin");

        //        Load page into web view

        webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent());

        return webView;
};

And back in the loadAndShow method, we’ll adjust it so that it only shows the window once the web view has loaded:

function loadAndShow(baseURL, onApplyMessage){
        //        ...

        const window = createWindow();
        const webView = createWebView(pageURL, onApplyMessage, () => {
                showWindow(window);
        });

        window.contentView = webView;

        _window = window;
};

Bingo! Now our window displays only when the web view has finished loading, avoiding that annoying visual flicker.

Conclusion

Congratulations, you’ve built your first Sketch plugin! 🎉

If you’d like to install and play around with Mosaic, you can download the complete plugin from GitHub. And before you go, here are a few resources that might be handy during the rest of your journey:

  • developer.sketchapp.com
    The official resource regarding Sketch plugin development. Contains several useful guides, as well as an API reference for the Sketch JavaScript library.
  • sketchplugins.com
    A fantastic and helpful community of Sketch plugin developers. Great for getting all your burning questions answered.
  • github.com/sketchplugins/plugin-directory
    Official, central GitHub repository of Sketch plugins. You can submit your plugins here and share them with the rest of the Sketch community!
Smashing Editorial
(mb, yk, il)
Reblogged 6 days ago from www.smashingmagazine.com

CSS Lists, Markers, And Counters

CSS Lists, Markers, And Counters

CSS Lists, Markers, And Counters

Rachel Andrew

2019-07-09T12:30:59+02:00
2019-07-10T11:35:59+00:00

Lists in CSS have particular properties which give us the standard list styling we expect. An unordered list gains a list bullet, of the type disc, and ordered lists are numbered. My interest in exploring lists in more detail came from some work I did to document the ::marker pseudo-element for MDN. This pseudo-element ships in Firefox 68 and is being released today. With the ::marker pseudo element available to us, we can start to do some interesting things with lists, and in this article, I’ll explain more.

Deconstructing A List

You may not have thought much about lists, although we use them frequently in our markup. Many things can be marked up quite logically as a list. While step-by-step instructions or ranked elements may naturally be described by an ordered list <ol>, many things in a design can be described using an unordered list <ul>. A very common usage of the element, for example, is to mark up navigation, as it is a list of destinations on the site. For our exploration, let’s start by finding out exactly what a list is in CSS.

As with many things in CSS, lists have some initial values applied to them. These values make them look like a list. These special values begin with the information that a list item has the display property with a value of list-item. This creates a block-level box, with an additional marker box. The marker box is where the list bullet or number is added.

Lists were defined early on in CSS, and much of the definition of lists as we use them today is from CSS2. The CSS2 specification describes a list item as follows:

“An element with display: list-item generates a principal block box for the element’s content and, depending on the values of list-style-type and
list-style-image, possibly also a marker box as a visual indication that the element is a list item.”

The principal block box is the main box of the element and contains all of the children as a list item can contain other markup. The marker box is then placed in respect to this principal box. The specification goes on to detail the fact that any background color will be only behind this principal box, and not the marker. Also that the marker can be set to one of a range of pre-defined values:

  • disc
  • circle
  • square
  • decimal
  • decimal-leading-zero
  • lower-roman
  • upper-roman
  • lower-greek
  • lower-latin
  • upper-latin
  • armenian
  • georgian
  • lower-alpha
  • upper-alpha
  • none
  • inherit

The Level 3 display specification defines display: list-item along with the other possible values for the display property. It refers back to CSS 2.1 — as do many CSS properties and values which come from CSS2 — but describes the list-item keyword as, “causing the element to generate a ::marker pseudo-element”.

The Level 3 specification also introduces the ability to create an inline list item with the two value syntax being used display: inline list-item. This is as yet unimplemented by browsers.

Creating Marker Boxes On Non-List Items

As with other values of display, it is perfectly valid to give any HTML element a display type of list-item (should you wish to generate a ::marker pseudo-element on the item). This will not cause the element to become a list item semantically, but instead it will only visually display as a list item, and therefore be able to have a ::marker. When we discuss the ::marker pseudo-element below, you will discover some cases where giving other elements display: list-item can be useful.

The CSS Lists Level 3 Specification: ::marker And Counters

The display specification expands and clarifies the definition of lists that we find in CSS2, however, there is also a specification which defines list behavior in detail: the CSS Lists Specification Level 3. As the basic behavior of list items is defined in display, this specification details the marker box generated when something has display: list-item along with the counters which are used by default whenever you create an ordered list. There is some potentially useful functionality accessed via these features.

The ::marker Pseudo-Element

The ::marker pseudo-element allows you to target the list marker — separately from the content of the list item. This was not possible in previous versions of CSS, therefore, if you changed the color or font size of the ul or li, this would also change the color and font size of the markers. In order to do something as seemingly simple as having different color list bullets than text, would involve either wrapping the content of the list item in a span (or using an image for the marker).

ul {
  color: #00b7a8;
}

ul span {
  color #333;
}

With the ::marker pseudo element, the simplest thing you might want to try is having a different bullet to text color, which means that instead of the code in the example above you can use:

ul {
    color: #333;
}

ul ::marker {
    color: #00b7a8;
}

You might also want to use a different size and font-family for the numbering on an ordered list.

ol ::marker {
  font-size: 200%;
  color: #00b7a8;
  font-family: "Comic Sans MS", cursive, sans-serif;
}

You can see all of these in a supporting browser by using my CodePen example:

See the Pen [Colored bullets with and without marker](https://codepen.io/rachelandrew/penVJQyoR) by Rachel Andrew.

See the Pen Colored bullets with and without marker by Rachel Andrew.

You could use the ::marker pseudo-element on non-list items. In the code below, I have set a heading to display: list-item. This gives it a bullet and therefore a ::marker box to target.

I have changed the bullet to use an emoji:

h1 {
  display: list-item;
}

h1::marker {
  content: "🐱";
}

In Firefox, you can see the emoji used as a marker.

See the Pen [Heading and marker](https://codepen.io/rachelandrew/pen/wLyyMG) by Rachel Andrew.

See the Pen Heading and marker by Rachel Andrew.

In the above example, I have used generated content in the rules for the marker. Only a small subset of CSS properties is available for use on ::marker. These include font properties and color, however, they also include the content property, for including generated content.

The addition of content as an allowed property for ::marker is recent, however, it is included in the Firefox implementation. The inclusion means that you can do things like include a string of text in a ::marker. It also raises additional possibilities for formatting of markers when you combine the use of counters with ::marker.

Browser Support And Fallbacks

For browsers that do not support the ::marker pseudo-element, the fallback is the regular marker that would have been displayed anyway. Unfortunately, we can’t currently use Feature Queries to detect support for selectors such as this pseudo-element right now, although there has been an issue raised about adding this to the specification. This means that you can’t fork your code to do one thing when you have support and something else if you do not. In most cases, falling back to the regular marker will be a reasonable solution.

Counters

Ordered lists have list numbering — something which is achieved by way of a CSS Counter. The CSS Lists specification therefore also describes these counters. We can access and create counters ourselves which, combined with the ::marker pseudo-element can give us some useful functionality. These counters can also be used in regular (non ::marker) generated content.

If I have a numbered list of steps (and I would like to write out “Step 1”, “Step 2”, and so on), I can do this by using generated content in my marker and appending the list-item counter, this represents the built-in counter:

::marker {
  content: "Step " counter(list-item) ": ";
}

An ordered list with Step 1, Step 2, and so on, before each list item

In Firefox, you will see the counter prefixed with the word “Step”.

See the Pen [Counters and marker](https://codepen.io/rachelandrew/pen/BgRaoz) by Rachel Andrew.

See the Pen Counters and marker by Rachel Andrew.

Nested Counters

If you have nested lists, a common way to number them is to have the top-level item a whole number, (1), then child items as (1.1, 1.2) and their children (1.1.1, 1.1.2), and so on. You can achieve this by using more functionality of counters.

When you nest HTML lists, you will end up with multiple counters of the same name — nested inside each other. The nest of counters can be accessed using the counters() function.

In the code below, I am using counters() to format my list markers as described above. The first argument for counters() is the name of the counter to use. I’m using the built-in list-item counter. The second argument is a string — this is what will be concatenated between output counters (I’m using a .). Finally, I add a : outside of the counter function but inside the value of content so that my counter output will be separated from the content by a colon.

::marker {
  content: counters(list-item,'.') ':';
  color: #00b7a8;
  font-weight: bold;
}

This gives me the output as in the image. If you are using a browser which supports ::marker and counters, then you can see it working in the CodePen example — try changing the string from a . to something else to see how that changes the output.

A set of nested lists

In Firefox, you will see nested list numbering separated by dots.

See the Pen [Nested counters](https://codepen.io/rachelandrew/pen/VJbwxL) by Rachel Andrew.

See the Pen Nested counters by Rachel Andrew.

What’s The Difference Between counter() And counters()?

The counter() function we used in the first example to write out our steps uses the innermost counter only. Therefore, in the situation where you have a set of nested lists, you will write out the counter which related to the level you are currently on.

The counters() function essentially writes out that whole branch and gives you the opportunity to concatenate a string between counters in the branch. So if you have a list item with a counter of 2 (which is part of a list nested inside a list item with a counter of 4), then the branch contains:

  • 4
  • 2

You can output this as 4.2 in the marker by using:

::marker {
  content: counters(list-item,'.');
}

Counters On Other Elements

Counters can be used on things which are not lists — either to output a marker — in which case the element will need to have display: list-item — or to output regular generated content. Counters are used extensively in book production, in order to enable chapter and figure numbering amount other things. There is no reason not to take a similar approach on the web, in particular for longer articles.

The CSS properties defined in the CSS Lists specification which deal with these counters are:

  • counter-set
  • counter-reset
  • counter-increment

To see how these work outside of lists we can look at an example of using counters to number the headings in a document.

The first thing I need to do is to create a counter for headers on the body element — ready for use. I’m using the counter-reset property to do this. The counter-reset and counter-set properties are very similar. The counter-reset property will create a new counter if a counter of the specified name does not already exist, but will also create nested counters as described above if a counter of that name does exist. The counter-set property will only create a new counter if there is no counter of that name. For this, use either property would work just fine, however, counter-set does not have as good browser support as counter-reset, so I am taking the practical route:

body {
  counter-reset: heading-counter;
}

Now that I have a counter, I can then use the counter-increment property on the selector for the headers; this should increment the counter every time the selector matches.

h2 {
  counter-increment: heading-counter;
}

To see the value, I need to output it to the document. I can do this by using Generated Content and adding it before the heading as shown in the following CodePen example:

h2::before {
  content: counter(heading-counter) ": ";
  color: #00b7a8;
  font-weight: bold;
}

See the Pen [Headings and counters](https://codepen.io/rachelandrew/pen/gNGjxq) by Rachel Andrew.

See the Pen Headings and counters by Rachel Andrew.

Alternatively, I could make the h2 element into a list-item and then use ::marker, as demonstrated below. As already detailed, using the ::marker element has limited browser support. In Firefox, you should see the counter used as the marker for the heading, while other browsers will show the default bullet.

h2 {
  display: list-item;
}

h2::marker {
  content: counter(heading-counter)  ": ";
  color: #00b7a8;
  font-weight: bold;
}

See the Pen [Headings, markers, and counters](https://codepen.io/rachelandrew/pen/pXWZay) by Rachel Andrew.

See the Pen Headings, markers, and counters by Rachel Andrew.

Counters On Form Elements

There is also a little bit of interactivity that you can achieve using CSS Counters — something that you might think you need JavaScript to do.

I have a form which has a number of required fields. The required status can be selected in CSS with a :required pseudo-class, and the fact that a field has not been completed can be detected by way of the :invalid pseudo class. This means that we can check for fields which are both required and invalid, and increment a counter. Then output that as generated content.

See the Pen [Counting required form fields](https://codepen.io/rachelandrew/pen/vqpJdM) by Rachel Andrew.

See the Pen Counting required form fields by Rachel Andrew.

How useful this is in reality is debatable — given that we can’t really do anything with that value other than stick it into generated content. There are also concerns with regard to generated content being inaccessible to certain screen readers, therefore any usage that is more than decorative would need to ensure other ways of accessing that information. Read, “Accessibility Support For CSS Generated Content” and the more recent information, “CSS Content Property Screen Reader Compatibility” for more details regarding accessibility and generated content.

However, it demonstrates that counters can achieve more useful things than simply numbering lists. It may be that one day that knowledge does come in handy to solve some problem you are working on.

Find Out More

This article ended up rather a long way from styling lists, despite the fact that everything I have described is found in the CSS Lists specification. You can find more information about the things described in the links below. If you have found an interesting use for CSS Counters, or can think of things you could use ::marker for, add a note in the comments.

Smashing Editorial
(il)
Reblogged 6 days ago from www.smashingmagazine.com

Yoast SEO 11.6 updates how-to structured data block, following Google’s changes

The latest update also includes more UX changes and bug fixes.

Please visit Search Engine Land for the full article.

Reblogged 6 days ago from feeds.searchengineland.com

Want to be a Better Social Media Marketer? Listen to These 13 Podcasts

The last time I went on vacation, Facebook and Instagram announced two big product changes that I was left scrambling to catch up on when I returned.

Know the feeling? If you work in social media marketing, my guess is you know it all too well.

Social media is constantly evolving, making today an exciting time to work in marketing. This can also mean that you sometimes feel as if you’re falling behind on your general social media knowledge and education.

The solution? Podcasts.

In this blog post, we put together a list of 10 podcast episodes that deliver helpful and actionable guidance for social media marketers looking to brush up on their skills in a quick and entertaining way.

1. Marketing Smarts with Kerry O’Shea

How ‘Dolphin Tale’ Brought 800,000 Visitors a Year to Clearwater Marine Aquarium

Click here to listen to this podcast episode

In this episode, Kerry O’Shea Gorgone speaks with Chief Marketing Officer of the Clearwater Marine Aquarium, Bill Potts. They discuss Winter the dolphin, whose story of recovery from losing her tail was chronicled in the movie Dolphin Tale. Thanks to their social media and public relations teams’ relentless work to get Winter’s story shared with local media outlets, she eventually became the star of a hit film (seriously, rent this movie).

In light of the Aquarium’s newfound fame, Potts talks about their strategies for maintaining the momentum of the Dolphin Tale films by investing in social media more than ever. In particular, they’ve experienced a lot of engagement by live streaming video of their animals on Facebook Live, Periscope, and Snapchat. (You can learn how to master Facebook Live with the help of this free guide.)

“[Live-streams are] not super-rehearsed. They really are authentic. We focus on the animal, we focus on the story, and we don’t script it. We have an outline of what we want to be reviewed during the live webcast, but we make sure they’re naturally delivered. They’re really not rehearsed. They just happen. We do schedule and plan them, and we do know what’s going to be discussed, but we make it really authentic. It’s a one-take deal.”

Key Takeaways:

  • All organizations have a story to tell, whether it’s about their mission, an individual, or a certain achievement. Give it the direction it needs to garner attention from media.
  • Don’t just talk about yourself: Get others to talk about you on social media and in the press to earn more attention. (Here’s a handy PR guide to help with that.)
  • Live streams should be raw, unscripted, and authentic: You can practice using the technology, but ultimately, remain flexible to allow room for more genuine content. (Check out this live streaming checklist before you get started.)
  • Don’t be afraid to experiment with how and where you’re sharing video content. For example, the aquarium turns over their Snapchat to trainers working with animals 1:1 so followers can see how the aquarium helps marine life up close.
  • Learn about your audience and where to reach them: For the aquarium, it’s mothers on Facebook.

Duration: 25:20

2. Online Marketing Made Easy with Amy Porterfield

How to Get Started with Facebook Live

Click here to listen to this podcast episode

This episode of Amy Porterfield’s marketing podcast features Kim Garst of Boom Social, where they discuss best practices and strategies for using Facebook Live. Main themes of this episode included determining how often to broadcast, apprehension about broadcasting live and making mistakes, and uncertainty about measuring success.

“I think the reason live video is so impactful (again, this is my opinion and what I’ve seen through my personal experiences and watching other people) is that people are so attracted to people who are not just real, but people that are relatable. In other words, they can see themselves having that issue.”

Key Takeaways:

  • Consistency is a contributor to successful live streams: Create a regular schedule on Facbeook Live or Periscope to expand your reach after you stop broadcasting live.
  • Carefully choose your broadcast’s headline: Remember, this is an opportunity to grab more attention from followers.
  • Incorporate an offer into pre-outreach for your Facebook Live event. For example, tell followers that you’ll be giving away promo codes, ebooks, or checklists that they can only download if they tune in.
  • Have a strategy to achieve a specific goal for every single broadcast, and don’t just talk for the sake of sharing.
  • Find a way to capture people’s attention while they scroll: Facebook only counts “Views” as users who watched for 10 seconds or more.

Duration: 55:31

3. Social Media Marketing with Michael Stelzner

Content Creation Hacks

Click here to listen to this podcast episode

This episode, hosted by Social Media Examiner Founder and CEO Michael Stelzner, focuses on social media content creation with the help of special guest and social media pro, Nick Westergaard.

In the interview, Westergaard discusses the fact that everyone knows they need to create content, but not everyone knows how to do it most effectively. Many content creators don’t operate with a comprehensive strategy, which can make people object putting in the work to make content pay off. Westergaard mentions the term “checklist marketing,” which he says refers to marketers tackling every new marketing strategy like an item on a to-do list without objectives or strategy in mind.

“You have to gamify it a little bit and think about, if you’re creating one thing, how many more things can I create out of this? … By planning one piece of content, I create many.”

Key Takeaways:

  • Try a team approach to social media content creation to both share the workload and curate a diverse array of content — even from colleagues who aren’t marketers.
  • Experiment with user-generated content: Develop a campaign around an event or hashtag so your followers are sharing photos and messages that you can share with your networks.
  • Repurpose content: If you’re writing a blog post or designing an infographic (here are some helpful templates for that), find a way to create smaller pieces of it that can be used as social media posts. Additionally, you can string smaller pieces of content together to create an ebook or guide.
  • Take part in #TBT: Align your older content with current events and re-share it on social media. This takes advantage of nostalgia marketing and re-promotes content you’ve already created.

Duration: 41:08

4. Savvy Social Podcast with Andréa Jones

How to Network with People on Social Media (Without Feeling Weird About It)

Click here to listen to this podcast episode

Andréa Jones looks into one of the ways that brands could grow their social audiences without buying ads: networking. It can sometimes feel strange meeting others on social media just to prospect for potential customers, but Jones covers a range of methods to make it easier.

The podcast had a Q&A style structure, where Jones’ LinkedIn followers asked questions about creating a brand presence on social media.

“The premise is simple: meet people on social media who would potentially give you money for your ‘thing.’ Simple yet incredibly challenging to execute because as soon as we start talking about what we do, it can feel… icky.”

Key Takeaways:

  • Have a people-first perspective. Don’t get spammy — be confident in the value of your offering and trust that organic social media marketing will be more effective than getting in your customer’s faces.
  • Understand the needs, wants, desires of your customers. Emphasize the ways your products or services will impact your network more than emphasizing yourself.
  • List what you do on your personal profile. You can share your work updates, anniversaries, and announcements on your profile to build your personal brand. This could make consumers curious about your company and want to learn more. 
  • A company’s social presence should reflect the brand’s personality. Keeping a consistent and reliable brand presence will help engage your target audience and lead them to connecting on social media.

Duration: 29:52

5. TED Radio Hour with Guy Raz

Why Do We Like What We Like?

Click here to listen to this podcast episode

In this episode of the TED Talks podcast, host Guy Raz interviews several TED speakers who’ve talked about branding:

  • Filmmaker and Producer of Super Size Me Morgan Spurlock discusses how brands impact our purchasing decisions.
  • Management Advisor and Author Joseph Pine touches on the power of authenticity.
  • Ogilvy & Mather Group’s Vice Chairman Rory Sutherland explores the real versus perceived value of different products.

Their discussions are varied and well worth the full listen, but the overarching theme was how brands’ perception impacts their success (or lack thereof). Pine mentions that customers make choices because they’re bought into the dreams and imagery surrounding big brands, and that once they start using the product, they start to believe the message.

“Ubiquity is the death of authenticity.”

Key Takeaways:

  • Take advantage of the opportunity to cultivate and promote what makes your brand unique. There’s always room for bragging on social media — just do it in moderation.
  • Be authentic and real, but don’t say that’s what you’re doing. Consumers want authenticity, not disingenuity.
  • Tell stories with a sense of place to drive greater authenticity: Set the stage when sharing blog posts, updates, and videos on social media so followers can see the kind of activities your organization is up to.
  • A/B test different types of post on social platforms to see how they perform comparatively: Consumers don’t objectively think a product or service is good or bad — branding and marketing messages impact their perception, and that’s in your hands.

Duration: 49:13

6. The Growth Show with Meghan Keaney Anderson

Episode 100: Guy Kawasaki’s Unconventional Advice on Growth

Click here to listen to this podcast episode

In this episode of The Growth Show, HubSpot CMO Kipp Bodnar sat down with Canva Chief Evangelist Guy Kawasaki to discuss Instagram Stories versus Snapchat Stories, Facebook Live video, and organizational growth challenges.

During the discussion, Kawasaki admits that he prefers Instagram to Snapchat due to its superior content discoverability features and analytics options. And when it comes to Facebook Live, he is bought in.

In fact, he mentions that while taking a break from streaming on vacation, his Facebook reach was only 400,000 users, versus the 1 million users he sees when he’s streaming regularly. (Spoiler alert: He also lets listeners in on his secrets to greater engagement during live streams — but you’ll have to listen to find out what they are.)

“I don’t want positive, supportive, wonderful, reinforcing engagement on social media. I want any kind of engagement.”

Key Takeaways:

  • Facebook Live drives greater engagement and reach than publishing recorded video or sharing a YouTube link.
  • When you’re streaming live on Facebook, have a second screen (and ideally a teammate) available to see what comments or questions are rolling in from your audience so you can answer them live.
  • Ask your audience questions while you’re streaming live to increase comments, Likes, and followers.
  • Publish regularly and frequently to increase engagement on social media platforms.

Duration: 35:01

7. Maximize Your Social with Neal Schaffer

The Influencer Marketing ROI of Creating and Publishing a Roundup Post

Click here to listen to this podcast episode

Influencer marketing can be a great way of reaching new audiences, so Neal Schaffer and Codrut Turcanu look into the value of using influencer marketing to promote roundup posts. When blogs post lists of offerings, they are making what’s known as a roundup post or crowdsourced article. An example of this might be “The 7 Best Ecommerce Software in 2019” or the blog post you’re reading right now!

Influencers can be excellent marketers as they have engaged audiences and can share content directly to them, leading to a lot of traffic. Schaffer and Turcanu discuss what the ROI of influencers sharing roundup articles to their networks.

“You want to ensure you’re engaging with the right people with the biggest impact.” 

Key Takeaways:

  • Think of the end result. It can be time consuming to find bloggers or influencers to promote your product or service, but if you know what your goal is, then you can start compiling the right lists of leads and partners to get going.
  • Identifying the right influencers is crucial. It’s important to find and engage the right people that have the greatest impact on your target network.
  • Roundup blog posts are beneficial for connecting with wider audiences. These kinds of posts pick up traffic from the organizations, services, and thought leaders featured in the article.
  • Roundups put you on the radar of influencers. Publishing a crowdsourced article helps build relationships and build your social community.

Duration: 23:47

8. Hashtagged with Jordan Powers

Focusing on Creating Content and Community Versus Being an Influencer with Dan Joyce

Click here to listen to this podcast episode

In this episode of Hashtagged, host Jordan Powers interviews Dan Joyce, a content creator on Instagram, about the cultivation of vibrant and engaged social media communities. Joyce was one of Instagram’s very first users.

They swap stories about how they started using Instagram first as a creative outlet, and then eventually as a tool for content creation and personal networking. As a professional content creator, Joyce initially began experimenting with Instagram, but it’s since evolved into a powerful network that photographers and other content creators can harness:

“[The] platform has provided a breadth of knowledge about photography and content creation in a way that makes big social network a lot smaller … There are so many types of content being shared on Instagram, it’s created its own ecosystem.”

Key Takeaways:

  • You can’t force becoming an influencer or thought leader, even on social media. Share lots of unique and creative content to grow your social network, and followers will come after.
  • Individuals and brands can use Instagram as a more professional portfolio of photographs and Snapchat as a more lighthearted photo log of their day-to-day.
  • Experiment with the types of posts you share on Instagram: Powers found that when his posts are more about content creation than networking, they end up performing better. (Here are 18 photo and video ideas for Instagram to try.)

Duration: 40:18

9. Inbound Marketing Today with Neil Brown

7 Social Media Mistakes Companies Make & How You Can Avoid Them

Click here to listen to this podcast episode

Inbound Marketing Today is hosted by Neil Brown, founder of the Brown Creative Group, and in this episode, he discusses common mistakes businesses are making on social media:

  1. Treating all social media sites as if they’re the same and not changing up how you share content.
  2. Too much automation.
  3. Not posting on social media frequently enough.
  4. Not responding to questions or comments.
  5. Deleting negative posts, comments, and reviews.
  6. Trying to be active on every social media channel.
  7. Not having a lead generation strategy.

“You want to use automation to make marketing more efficient, not to appear as a bot. Social media should be social.”

Key Takeaways:

  • Social media is an arm of your customer service team: Aim to be helpful, positive, and delightful to your customers.
  • It’s better for engagement to have a comprehensive strategy for only two social media platforms than to post at random on all platforms.
  • Maintain your voice’s authenticity. You’re a human speaking for an organization, so don’t forget to be real, and connect with people when they seek assistance or give feedback.

Duration: 12:14

10. Social Pros with Jay Baer and Adam Brown

Why Most Social Media Writing Sucks & How to Fix It

Click here to listen to this podcast episode

In this episode of Convince and Convert’s Social Pros, hosts Jay Baer and Adam Brown interview Josh Bernoff — chief troublemaker at Without Bullsh*t — about writing quality content for social media.

Bernoff’s mission is to eliminate convoluted writing from marketing, and he thinks it’s a challenge because we were rewarded for writing long papers when we first learned to write in school. Now, that experience is impacting social media posts, press releases, and blog posts in a detrimental way.

“You’re not creating art. You’re creating effective communication, and there’s nothing wrong with doing that simply and directly.”

Key Takeaways:

  • Get to the point. You should aim to say what you mean in the first 2-3 sentences of whatever you’re writing.
  • Adopt Baer’s ROAM content marketing checklist: Who are the readers? What are your objectives? What follow-up action do you want to inspire from the reader? What impression will people have of your organization when they read your content?
  • Always have another set of eyes look over your content, even Facebook captions. Never publish a first draft.

Duration: 53:40

11. #AskGaryVee with Gary Vaynerchuk

YouTube Growth Strategies, Business Risks & VanyerMedia’s New Office

Click here to listen to this podcast episode

In his podcast #AskGaryVee, Digital Marketing Expert Gary Vanyerchuk answers questions from his followers (delightfully coined “VanyerPeeps”), and his entertaining responses make it worth the listen. At the beginning of this episode, Vanyerchuk answers questions from a VaynerPeep about strategies for hacking YouTube growth.

Vanyerchuk believes that for all content creation — be it blog, video, or social media — the distribution is more important than the creation, and that those priorities are often the opposite to modern marketers. It’s not enough to write a great blog post, or produce a great YouTube video: it has to be seen and picked up by the right people, and that won’t happen unless you hustle for it.

“You have to continue to bring value and produce good content, but you also need people to know about it.”

Key Takeaways:

  • Try collaborating with other YouTubers or influencers in your space on social media. If you can’t offer them exposure, what can you offer them in exchange for their partnership? Always offer value.
  • Use targeted hashtags on Instagram to grow your audience there. Do some research to determine which tags are generating the highest levels of engagement.
  • Join forums within your industry communities to develop a network of support that you can reach out to for social sharing, promotion, and participation in your social media campaigns.

Duration: 17:55 (YouTube answer ends at 8:00)

12. Manly Pinterest Tips with Jeff Sieh and Erik Fisher

Pinterest Growth And Instagram Shoppable Posts

Click here to listen to this podcast episode

Pinterest is growing, and organizations can really benefit from marketing on one of the biggest media brands. Jeff Sieh took a look with Erik Fisher at how to best connect with Pinterest’s quarter of a billion users around the world as well as shopping on Instagram.

“According to a Nielsen study, 98% of Pinners, they go out and try ideas that they find on Pinterest. And that’s way more than 71% of the other social media platforms.”

Key Takeaways:

  • Pinterest is a place to reconnect with yourself. Compared to other platforms where the idea is to connect with other people, Pinterest is for keeping track of things that you like. Driving traffic from Pinterest therefore reflects a genuine interest in your offering.
  • On Pinterest, you’re not competing with social content. Since Pinterest isn’t a typical social networking platform, your products won’t have to compete with videos of your friends’ kids for your feed’s attention.
  • 98% of pinners go out to try ideas they find on Pinterest. Promoting a product on Pinterest makes a ton of sense — consumers are turning to their pinboards to make purchasing decisions.
  • Instagram Shopping is hot. As a consumer, you can seamlessly buy items off Instagram Stories, and as a seller, you can track consumer behavior in your Instagram store.

Duration: 24:00

13. Social Media Social Hour with Tyler Anderson

Behind the Data: A Quantitative Look at the Future of Social Media

Click here to listen to this podcast episode

In this episode of Social Media Social Hour, presented by Scoreboard Social and Casual Fridays, host Tyler Anderson interviews CEO of the Social Fresh, Jason Keath, to discuss the outlook of the future of social media. Social Fresh recently conducted a survey of over 500 participants about how brands are measuring, or not measuring, the ROI of their social media strategies.

Anderson and Keath discussed many of the findings in the report, with results often circling back to the outlook that video will continue to dominate social media in terms of engagement and ROI. This episode provides in-depth analysis and conversation without being too lengthy, with lots of helpful tips and actionable next steps for listeners along the way.

“No one is seeing a return on what they’re doing on Snapchat right now… but people are passionate about the engagement opportunity.”

Key Takeaways:

  • Prioritize social networks that deliver the greatest ROI: According to the report, those networks are Facebook, Twitter, Instagram, and LinkedIn (in that order).
  • Instagram is projected to overtake Twitter in terms of popularity and ROI. Keath speculates that it’s because Instagram is less saturated than Twitter, which leads to greater engagement.
  • Get the ball rolling on a video strategy: The number of respondents creating video assets on a monthly basis is growing — it ranked third for assets marketers are creating after images and blog posts.

Duration: 35:10

Are you a social media marketer? What podcasts do you listen to that we missed? Share with us in the comments below.

Reblogged 6 days ago from blog.hubspot.com

13 Great Landing Page Examples You'll Want to Copy in 2019

While many landing pages look different and use a variety of interesting strategies to pull in audiences, they all serve one major purpose. These pages get website visitors to convert to the next stage in the buyer’s journey.

Rather than serving as a basic advertisement that shows a customer a product, a landing page aims to engage and delight a customer by offering them something that relates to the product or the company’s industry. When they fill out the form and receive a reward of interesting content, they might be even more likely to trust your brand and become a customer.

Here’s a quick example. If a business wants to sell an AI product that helps salespeople, they might create a landing page that offers audiences a free video on how to use AI in the sales industry. Interested audiences might offer their contact information in exchange for the valuable information. If they enjoy the video they’ve received, they might be more likely to respond to or purchase a product from a company rep who calls them.

In another scenario, a publishing company that targets an audience of chief executives might create a landing page that invites audiences to sign up for a webinar hosted by an executive at a major company.

After giving their email address on the signup form presented on the landing page, the leads get an email with the webinar dates and log in information, as well as instructions on how to sign up for the publication’s newsletter or subscription. If the user is pleased by the webinar, they might sign up for the newsletter or a subscription to keep up with similar publication content.

Although their purpose is simple enough in theory, actually designing a successful landing page requires some detailed planning and creative testing.

Even after launching your landing page, you’ll want to pay attention to conversion rates to see how well it’s doing.

To determine your conversion rate, simply divide the number of conversions a webpage generates by the number of people who visited that page.

If your conversion rate isn’t close to the average just yet, don’t worry. Nailing those percentages can be a bit challenging at first, especially is you have a lot of regular page visitors. Luckily, there are a number of simple conversion rate optimization strategies that can help you boost your current rate quickly.

Regardless of what your business is selling or the conversion action you hope to instigate, it’s helpful to get inspired by seeing what other great landing pages look like. And because there’s no one “right” way of designing a landing page, you’ll want to check out examples from lots of different industries for different stages of the buying process.

Want to get inspired? Check out the great landing page examples below.

We don’t have access to the analytics for each of these landing pages, so I can’t tell you specifically how well they convert visitors, contacts, leads, and customers. But many of them do follow best practices while also implementing a few new experiments that could give you ideas for your own landing pages.

13 Great Examples of Landing Page Design

1. Lyft

We love that on Lyft’s landing page, they zero in on their drivers’ main motivation: earning money easily.

We also love that, in addition to the “Apply Now” form, drivers can type their city and the number of hours they might drive for Lyft in a week to calculate how much they’d make. When visitors fill out that information and press “Calculate,” they aren’t taken to a new page. Instead, they see a dollar amount followed by a new call-to-action button to “Apply Now” (which, once clicked, takes drivers up to the form).

By offering these two conversion paths, they’re able to address two different types of people in the conversion path: those who are ready to make the decision now and those who need a little more information before they convert.

2. The Professional Wingman

Okay, so the whole idea of having a professional wingman to help you find dates and a meaningful relationship is already pretty cool. But when you’re faced with the prospect of hiring one, it also raises questions. How does it work? How much does it cost? Is this really going to help me?

That’s why we love this landing page for Thomas Edwards, the original Professional Wingman himself, which outlines exactly what a complimentary coaching session is going to achieve. Plus, it’s clear that it’s complimentary, thanks to the boldly-colored call-to-action button above the fold.

Once you click that button, you aren’t taken to a new page. Instead, an interstitial form appears right there. And while it does request a lot of information — some of it a bit personal — it also sends the message that The Professional Wingman is going to take this seriously, but only if you do, too.

professional wingman landing page

3. Muck Rack

This landing page design has it all. It’s visually appealing and interactive, offers scannable yet descriptive headers about Muck Rack’s services, and uses quotes from industry professionals as social proof. Plus, the page is intuitive and easy to navigate.

The cool part about this landing page is that it can appeal to both of Muck Rack’s audiences. The top of the page is split into two, featuring their two different services side by side. Once a visitor moves his or her mouse over either of the “find journalists” or the “build free portfolio” CTAs, a very simple form appears — and that’s important, so as not to distract the user from the task at hand.

muckrack landing page

4. Cigital

There are a few things that make this Cigital landing page work. It has simple and relevant imagery. The headline is straightforward and the description of the ebook informs viewers of the specific value they will get by downloading it. There is only one call-to-action — “READ THE EBOOK” — that stands out on the page thanks to a bright yellow CTA button.

The only thing we’d change about this landing page is that we’d remove the navigation bar at the top. They tend to distract visitors and lead them away from the intended action. Not only is this a landing page design best practice, but we’ve also conducted A/B tests that’ve shown removing navigation links from landing pages increases conversion rates.

Cigital landing page

5. Khan Academy

The hard part about using your homepage as a landing page is that you have to cater to several different types of audiences. But Khan Academy’s homepage does that very well. This page is clearly designed for three different types of visitors: those who want to learn something, those who want to teach, and parents who are interested in using Khan Academy for their kids. Plus, how motivational is the emblazoned “You can learn anything” text at the top?

The remainder of the page is designed for viewers who are not completely familiar with Khan Academy. It colorfully and largely spells out the key benefits of using the learning platform — all of which are easy to scan and understand. There’s also a recurring CTA: “Start learning now.” As soon as viewers feel they have enough information, they can click the CTA to get taken back up to the form at the top of the page without having to scroll.

khan academy landing page

6. Club W

A little bit of delightful copy can go a long way on your landing page. We love the playful little aside — “(Hint: It’s Wine)” — that Club W included below the header of their corporate gifting landing page. It humanizes the brand and makes them likable, which could have a positive impact on their conversion rate.

The images below that header make a nice use of negative space, showing the user exactly what his or her gift recipient might actually receive, should they choose to gift with Club W. And, of course, there’s that bold call to action — “Email Us”.

The one thing we’d change? The CTA prompts the users email software to open, which drives traffic away from the site and the browser entirely. A form might be more effective here — not only would Club W be able to dictate what information it wants to capture, but also, it would keep the user on-site.

club w landing page

7. Codecademy

I like this page because it’s simple in both copy and design. The image above the fold is a computer screen displaying an HTML bracket with a blinking cursor — a whimsical, clear visual to accompany the form on the right.

The form itself is simple and only requires an email address, username, password, and a validation that you’re not a robot to create an account. Or, you can just use your Facebook or Google Plus login, shortening the conversion path even further.

For visitors who need more information before creating an account, the landing page also offers a video below the fold that explains their concept and value by way of a real-life success story. Again, this helps make the potentially intimidating world of coding more approachable for beginners.

Those who need even more convincing can continue scrolling for additional testimonials and other forms of social proof.

codecademy landing page

8. Poached

I don’t think we’ve ever lived in a time when, culturally, we’ve been so food-obsessed. Poached has turned that into a B2B model with a platform to connect proprietors and culinary talent.

When you visit the homepage, there’s no mystery about what you’re there to do — the giant “Post a job” and “Choose a city” calls to action help with that. And once you click on one of them, you’re taken to a no-frills form to become a member or log in, or a list of jobs in each city. It’s colorful and comprehensive — and, it makes us hungry.

poached landing page

9. Breather

Here’s another example of clever, delightful design on a landing page. As soon as you visit Breather.com, there’s an instant call to action: indicate where you want to find a space. Plus, it uses location services to figure out where you are, providing instant options nearby.

We love how Breather used simple, to-the-point copy to let the visitor know what the company does, followed immediately by the CTA to select a city. And if you need to scroll down for more information, you can see that Breather played with the microcopy with personality (“no commitment, ever”), reminding us there are real humans behind the design. That brings us a little closer to the brand. The negative space and soothing color scheme are also aligned with the product — essentially, room to breathe.

breather.gif

10. Startup Institute

Visitors to your website won’t hand over their personal information without knowing what they’re going to get in return. On its landing page, Startup Institute makes abundantly clear what will happen after you apply by listing a Q&A right beside the form. It might prompt some people to say, “They read my mind!”

To avoid hesitancy to fill out a form, use your landing page to set expectations upfront. That clears the air, and can also weed out the people who don’t take your content, product or service seriously.

Startup Institute landing page

11. Edupath

Who is your landing page’s target audience? While most of Edupath’s website content is directed toward students, there are sections dedicated to advising parents on helping their teenagers through college applications and SAT preparation. The landing page below is in one of these sections.

When parents fill out their teenager’s name, email address, and mobile number, a link to download the Edupath app is sent directly to them. The folks at Edupath know students are likely to do something if their parents ask them to — especially if it means they don’t have to surrender their phones.

Plus, it’s an easy, one-click process. This whole conversion path is a clever and helpful way to get the apps on more students’ phones by way of their parents.

edupath landing page

12. Taster’s Club

If there’s anything we enjoy more than a fine whiskey, it’s a whiskey club homepage that makes it easy to either join or learn more about membership. Case in point: Taster’s Club, which immediately serves up those very two CTAs on its landing page — which also happens to be its homepage.

For those to wish to learn more, clicking that CTA will immediately scroll the user down to colorful, image-rich details on what a Taster’s Club membership includes. Keep scrolling, and you get user testimonials.

But clicking the “Join Now” button is where the real fun begins. After doing that, you get to pick your poison — that is, the type of whiskey you like the most — and view the membership or gifting options available for it. Once you make your selections, you’re taken to an easy-to-navigate checkout page to enter your payment information. Good design and ease of use? We’ll drink to that.

taster's club landing page

13. Microsoft IT Showcase

The landing page below has been used to market and generate leads for one episode of Microsoft’s IT Showcase webinar series.

Microsoft IT Showcase Webinar Landing page

This simple and straightforward design does a great job of presenting why the webinar being offered is important to IT professionals. Along with a quick blurb describing what the webinar will discuss, the page also includes links to similar webinars, details on the speakers, and links to Microsoft resources that touch on the topics that will be discussed.

An IT company which has access to thought leaders or experts in their industry could similarly use this webinar landing page strategy to generate both leads and prospective customer trust. Audiences who feel informed after reading the landing page might sign up expecting the webinar to be insightful.

If the webinar seems informative and credible, these audiences will think that the IT company has an expertise in the product and might have quality product offerings. This will make them more willing to talk to a representative to learn more or purchase a product.

Ready to build your landing page?

If these examples have inspired you, but you’re not a design expert, we’ve also created a great list of free, professionally designed landing page templates.

If you’re looking for more landing page design examples, check out some of our favorite HubSpot landing page examples. You can also check out this quick guide to landing page design.

Reblogged 6 days ago from blog.hubspot.com

What two big studies tell us about the state of local marketing

New research from SOCi and FreshChalk point toward best practices and reveal how most local marketers are failing to execute.

Please visit Search Engine Land for the full article.

Reblogged 6 days ago from feeds.searchengineland.com

SMX replay: Create dashboards that inform and persuade

Sam Marsden of DeepCrawl explains how to use data visualization to get faster buy-in from management and stakeholders.

Please visit Search Engine Land for the full article.

Reblogged 1 week ago from feeds.searchengineland.com