CSS Tricks RSS

CSS-Tricks

https://css-tricks.com
Tips, Tricks, and Techniques on using Cascading Style Sheets.
Sat, 08 Apr 2017 01:03:46 +0000
en-US
hourly
1
https://wordpress.org/?v=4.7.3
45537868
Pong with SVG.js
https://css-tricks.com/pong-svg-js/
https://css-tricks.com/pong-svg-js/#respond
Fri, 07 Apr 2017 14:33:30 +0000

https://css-tricks.com/?p=253412
<![CDATA[Everybody loves the vintage game Pong, right? We sure do. What's more fun? Building it yourself!

That's why we decided to create one with SVG.js – to highlight some aspects of our library. It might seem like a complex idea for a small tutorial, but as you’ll see, it’s simpler than it sounds. Let’s dive into it!

Here’s the finished product:

See the Pen Fully functional Pong game with effects by Wout Fierens (@wout) on CodePen.

Getting…


Pong with SVG.js is a post from CSS-Tricks

]]>
<![CDATA[Everybody loves the vintage game Pong, right? We sure do. What's more fun? Building it yourself!

That's why we decided to create one with SVG.js – to highlight some aspects of our library. It might seem like a complex idea for a small tutorial, but as you’ll see, it’s simpler than it sounds. Let’s dive into it!

Here’s the finished product:

See the Pen Fully functional Pong game with effects by Wout Fierens (@wout) on CodePen.

Getting started

SVG.js is available through Github, npm, bower or CDN.js. There are plenty of options for getting your hands on SVG.js, so use whatever you are most comfortable with.

Start out by creating a new HTML document and include the library. Create an empty

to serve as a wrapper for the SVG document, and give it an id attribute. Something like pong should be suitable for this project:



Next, initialize the SVG.js instance by referencing the wrapper. At this point, it’s also a good idea to define a width and height for the game which makes it easier to modify them later on.

// define width and height
var width = 450, height = 300

// create SVG document and set its size
var draw = SVG('pong').size(width, height)

Now you’re ready to start building the game.

Drawing Game Elements

The Background

The background should cover the whole document, so we’re using a and give it a neutral grayish color. First, we’ll draw the left player in green. Then, we’ll draw the right one by cloning the left one and coloring it pink.

// draw background
var background = draw.rect(width, height).fill('#E3E8E6')

We’ll also need a vertical, dashed line in the middle to distinguish the player fields.

// draw line
var line = draw.line(width/2, 0, width/2, height)
line.stroke({ width: 5, color: '#fff', dasharray: '5,5' })

See the Pen Pong Background by Wout Fierens (@wout) on CodePen.

Paddles and the Ball

Pong wouldn’t be Pong without paddles and a ball. First, we’ll draw the left player in green. Then, we’ll draw the right one by cloning the left one and coloring it pink.

var paddleWidth = 20, paddleHeight = 100

// create and position left paddle
var paddleLeft = draw.rect(paddleWidth)
paddleLeft.x(0).cy(height/2).fill('#00ff99')

// create and position right paddle
var paddleRight = paddleLeft.clone()
paddleRight.x(width-paddleWidth).fill('#ff0066')

For the ball we’re going to use a circle with a diameter of 20 and place it in the center of the court:

// define ball size
var ballSize = 20

// create ball
var ball = draw.circle(ballSize)
ball.center(width/2, height/2).fill('#7f7f7f')

See the Pen Pong Paddels and Ball by Wout Fierens (@wout) on CodePen.

Score board

Finally, we will need a scoreboard which we will add at the top of the court.

// define initial player score
var playerLeft = playerRight = 0

// create text for the score, set font properties
var scoreLeft = draw.text(playerLeft+'').font({
  size: 32,
  family: 'Menlo, sans-serif',
  anchor: 'end',
  fill: '#fff'
}).move(width/2-10, 10)

// cloning rocks!
var scoreRight = scoreLeft.clone()
  .text(playerRight+'')
  .font('anchor', 'start')
  .x(width/2+10)

That’s all! Now we have all game elements, let’s move on to game logic.

See the Pen Pong Scoreboard by Wout Fierens (@wout) on CodePen.

Game logic

We’ll start out by writing an update function which will update the state of our game and game elements.

// random velocity for the ball at start
var vx = Math.random() * 500 - 250
  , vy = Math.random() * 500 - 250

// update is called on every animation step
function update(dt) {
  // move the ball by its velocity
  ball.dmove(vx*dt, vy*dt)

  // get position of ball
  var cx = ball.cx()
    , cy = ball.cy()

  // check if we hit top/bottom borders
  if ((vy < 0 && cy  0 && cy >= height)) {
    vy = -vy
  }

  // check if we hit left/right borders
  if ((vx < 0 && cx  0 && cx >= width)) {
    vx = -vx
  }
}

When we run this, nothing will happen, because we didn’t call the update function yet. This will be done using JavaScript’s native requestAnimationFrame feature, which will allow us to do smooth animations. To make this work, a handler is registered to periodically call our update function:

var lastTime, animFrame;

function callback(ms) {
  // we get passed a timestamp in milliseconds
  // we use it to determine how much time has passed since the last call

  if (lastTime) {
    update((ms-lastTime)/1000) // call update and pass delta time in seconds
  }

  lastTime = ms
  animFrame = requestAnimationFrame(callback)
}

callback()

Yay! The ball is jumping around! But, our paddles are still pretty useless at the moment. So, let’s do something about that and insert paddle collision detection. We’ll only need it on the x-axis:

var paddleLeftY = paddleLeft.y()
  , paddleRightY = paddleRight.y()

// check if we hit the paddle
if ((vx < 0 && cx  paddleLeftY && cy  0 && cx >= width - paddleWidth && cy > paddleRightY && cy < paddleRightY + paddleHeight)) {
  // depending on where the ball hit we adjust y velocity
  // for more realistic control we would need a bit more math here
  // just keep it simple
  vy = (cy - ((vx < 0 ? paddleLeftY : paddleRightY) + paddleHeight/2)) * 7 // magic factor

  // make the ball faster on hit
  vx = -vx * 1.05
} else ...

Better, now the ball is aware of the paddles. But a few other things are still missing:

  • the score is not updating when the border is hit
  • paddles are not moving
  • the ball should reset when a point was scored

Let’s work through this list from top to bottom.

See the Pen Pong jumping ball by Wout Fierens (@wout) on CodePen.

Update the score

To update our score, we need to hook into collision detection to the left or right wall:

// check if we hit left/right borders
if ((vx < 0 && cx  0 && cx >= width)) {
  // when x-velocity is negative, its a point for player 2, else player 1
  if (vx < 0) { ++playerRight }
  else { ++playerLeft }

  vx = -vx

  scoreLeft.text(playerLeft + '')
  scoreRight.text(playerRight + '')
}

See the Pen Pong jumping ball by Wout Fierens (@wout) on CodePen.

Moving the user-controlled paddle

The right paddle will be controlled by the keyboard, and that’s a piece of cake with SVG.js:

// define paddle direction and speed
var paddleDirection = 0  // -1 is up, 1 is down, 0 is still
  , paddleSpeed = 5      // pixels per frame refresh

// detect if up and down arrows are prssed to change direction
SVG.on(document, 'keydown', function(e) {
  paddleDirection = e.keyCode == 40 ? 1 : e.keyCode == 38 ? -1 : 0
});

// make sure the direction is reset when the key is released
SVG.on(document, 'keyup', function(e) {
  paddleDirection = 0
})

So what are we doing here? First, we call SVG.on, which lets us bind an event listener to any node (not only SVG.js objects). We’ll listen to the keydown event to detect if either the up (38) or the down (40) key is pressed. If that’s the case, the paddleDirection will be set to -1 or 1 respectively. If another key is pressed, the paddleDirection will be 0. Lastly, when any key is released, the paddleDirection will be reset to 0.

The update function will do the actual work of moving the paddle, based on the user input. So we’ll add the following code to the update function:

// move player paddle
var playerPaddleY = paddleRight.y();

if (playerPaddleY = height-paddleHeight && paddleDirection == 1) {
  paddleRight.y(height - paddleHeight)
} else {
  paddleRight.dy(paddleDirection * paddleSpeed)
}

We prevent the paddle from exiting the court by testing its y position. Otherwise, the paddle will be moved by a relative distance using dy().

See the Pen Pong user controlled paddle by Wout Fierens (@wout) on CodePen.

Moving the AI paddle

A good opponent will make the game worthwhile. So we’ll have the AI player follow the ball, with a predefined difficulty level. The higher the difficulty, the faster the AI paddle will respond.

First define the difficulty value, defining the AI’s speed:

var difficulty = 2

Then add the following code to the update function:

// get position of ball and paddle
var paddleRightCy = paddleRight.cy()

// move the left paddle in the direction of the ball
var dy = Math.min(difficulty, Math.abs(cy - paddleRightCy))
paddleRightCy += cy > paddleRightCy ? dy : -dy

// constraint the move to the canvas area
paddleRight.cy(Math.max(paddleHeight/2, Math.min(height-paddleHeight/2, paddleRightCy)))

See the Pen Pong user controlled paddle by Wout Fierens (@wout) on CodePen.

Score!

Wait, this isn’t right! The game goes on even after one of the players scored. Time to include a reset function to move all game elements to their initial position using animations:

function reset() {
  // reset speed values
  vx = 0
  vy = 0

  // position the ball back in the middle
  ball.animate(100).center(width / 2, height / 2)

  // reset the position of the paddles
  paddleLeft.animate(100).cy(height / 2)
  paddleRight.animate(100).cy(height / 2)
}

The reset function should be called if one of the players misses the ball. To make that happen, change the failure detection by removing the vx = -vx line and adding the reset() call:

// check if a player missed the ball
if ((vx < 0 && cx  0 && cx >= width)) {
  // when x-velocity is negative, its a point for player 2, else player 1
  if (vx < 0) {
    ++playerRight
  } else {
    ++playerLeft
  }

  // update score
  scoreLeft.text(playerLeft)
  scoreRight.text(playerLeft)

  reset()
}

We also need to make sure the initial vx and vy values are set to 0. So the game does not start without our input. To be able to indicate the first serve, we’ll add a click listener to the SVG document:

draw.on('click', function() {
  if (vx === 0 && vy === 0) {
    vx = Math.random() * 500 - 250
    vy = Math.random() * 500 - 250
  }
})

See the Pen Pong with start and reset by Wout Fierens (@wout) on CodePen.

Encore

Of course, there is a lot left to improve on the game, but the purpose of this tutorial is to teach about SVG and in particular about SVG.js. We want to leave you with some visual effects to spice up the game.

Ball color

It would be nice to have the color of the ball change while approaching the opposite opponent. This is done by leveraging the power of the morph method on the SVG.Color class. We’ll detect the position of the ball, and gradually assign the color of the opposite opponent, based on the position of the ball on the x-axis.

We’ll start by initializing a new instance of SVG.Color:

var ballColor = new SVG.Color('#ff0066')

Next, we’ll define the target color by calling the morph() method:

ballColor.morph('#00ff99')

This will set a start color, being #ff0066 and an end color, being #00ff99. Using the at() method on SVG.Color, we can tween the color based on a given position between 0 and 1. So by adding the following code to our update function, we can change the color of the ball while it moves:

ball.fill(ballColor.at(1/width*ball.x()))

That wasn’t hard at all, right?

Boom!

Imagine a huge color blast when the opponent missed the ball. That would make it even more fun to win a point. To achieve this, we’ll use a radial gradient. It will appear where the ball has hit the wall and then quickly fade out. Once faded out, the object carrying the gradient will be deleted from the scene. To achieve this, we’ll add another function called boom including the required logic:

function boom() {
  // detect winning player
  var paddle = vx > width/2 ? paddleLeft : paddleRight

  // create the gradient
  var gradient = draw.gradient('radial', function(stop) {
    stop.at(0, paddle.attr('fill'), 1)
    stop.at(1, paddle.attr('fill'), 0)
  })

  // create circle to carry the gradient
  var blast = draw.circle(300)
  blast.center(ball.cx(), ball.cy()).fill(gradient)

  // animate to invisibility
  blast.animate(1000, '>').opacity(0).after(function() {
    blast.remove()
  })
}

See the Pen Fully functional Pong game with effects by Wout Fierens (@wout) on CodePen.

Conclusion

That’s it! You just created a working Pong game using SVG.js. In the next tutorial, we will cover how to convert this blob of code into a reusable SVG.js plug-in, while adding new features and easy configuration to the game.


Written by Ulrich-Matthias Schäfer & Wout Fierens.


Pong with SVG.js is a post from CSS-Tricks

]]>
https://css-tricks.com/pong-svg-js/feed/
0
253412

Interesting Takes on Log in / Sign Up Forms
http://mediatemple.net/blog/tips/interesting-takes-log-sign-forms/
https://css-tricks.com/interesting-takes-log-sign-forms/#respond
Fri, 07 Apr 2017 14:16:11 +0000

https://css-tricks.com/?p=253504
<![CDATA[A roundup of simple forms that have interesting UI interactions and animations.

I can't guarantee the final demo for each of them is perfectly accessible or measurably improves UX or anything, but that doesn't mean that you can't take inspiration from the ideas and make sure your implementation of them does.

Direct Link to ArticlePermalink


Interesting Takes on Log in / Sign Up Forms is a post from CSS-Tricks

]]>
<![CDATA[A roundup of simple forms that have interesting UI interactions and animations.

I can't guarantee the final demo for each of them is perfectly accessible or measurably improves UX or anything, but that doesn't mean that you can't take inspiration from the ideas and make sure your implementation of them does.

Direct Link to ArticlePermalink


Interesting Takes on Log in / Sign Up Forms is a post from CSS-Tricks

]]>
https://css-tricks.com/interesting-takes-log-sign-forms/feed/
0
253504

Can Class Names Trigger Safe Search Filters?
https://css-tricks.com/can-class-names-trigger-safe-search-filters/
https://css-tricks.com/can-class-names-trigger-safe-search-filters/#comments
Fri, 07 Apr 2017 14:08:56 +0000

https://css-tricks.com/?p=253502
<![CDATA[I got a tweet about this a while back, and it's been on my list of things to attempt to start a discussion about. Or even better, gather some real data about. It also might be a smidge related to SEO (as the asker leads with), and since yesterday's baby thought about SEO, it reminded me of this.

Here’s the question:

Hi @chriscoyier can CSS class name affect SEO? i.e. can class name “sex” for element with M/F …


Can Class Names Trigger Safe Search Filters? is a post from CSS-Tricks

]]>
<![CDATA[I got a tweet about this a while back, and it's been on my list of things to attempt to start a discussion about. Or even better, gather some real data about. It also might be a smidge related to SEO (as the asker leads with), and since yesterday's baby thought about SEO, it reminded me of this.

Here’s the question:

//platform.twitter.com/widgets.js

In other words, HTML like this:

Sex:


Male

Female

Yes, please

Heyyy-ooo

Honk honk

Wakka Wakka

Silly attempts to thwart being gender normative aside, is simply the presence of the word “Sex” on the page enough to trigger warnings, blockage, or exclusion from certain apps? Perhaps an app using Google Safe Browsing APIs, a firewall of sorts configured for blocking certain content, or some other kind of software designed to filter web content.

What if your business was Barry’s Delicious Smooth Mart so you prefixed a bunch of your CSS selectors:

.bdsm-header {
  background: papayawhip;
}

Will there be unintended consequences there?

I’m having a bit of Deja Vu about this conversation, in which I remember seeing a conversation about this somewhere where someone said this has indeed caused some minor problems for them, but I can’t seem to dig that up right now.

In fact, I don’t have any personal stories or data to share with you on this subject, I just wanted to open it up for comments from folks that actually do have some data.

In spending some time searching around about this issue, I found plenty of “experts” chiming in saying “no, CSS classes don’t affect anything.” That stands to reason, but there is no data cited, references provided, or proof supplied. But also note in our first example, the text we were worried about is “sex”, and it doesn’t only appear in classes, but other attributes as well, not to mention the actual visible text of the label.

So if you know something for real, let us know below.


Can Class Names Trigger Safe Search Filters? is a post from CSS-Tricks

]]>
https://css-tricks.com/can-class-names-trigger-safe-search-filters/feed/
1
253502

Container Query Discussion
https://css-tricks.com/container-query-discussion/
https://css-tricks.com/container-query-discussion/#comments
Thu, 06 Apr 2017 22:10:32 +0000

https://css-tricks.com/?p=253471
<![CDATA[Right now, we have the power to write CSS that only applies when the browser window itself is at certain widths or heights. Breakpoints, as it were. Super useful. What we don't have (natively) is the ability to write conditional CSS based on any particular elements (or "containers") properties.

It's going on 2 years since the RICG decided to tackle this. I’m not exactly sure what the status is there. It seems a bit on pause, but that doesn’t …


Container Query Discussion is a post from CSS-Tricks

]]>
<![CDATA[Right now, we have the power to write CSS that only applies when the browser window itself is at certain widths or heights. Breakpoints, as it were. Super useful. What we don't have (natively) is the ability to write conditional CSS based on any particular elements (or "containers") properties.

It’s going on 2 years since the RICG decided to tackle this. I’m not exactly sure what the status is there. It seems a bit on pause, but that doesn’t mean the entire discussion is on pause.

From what I hear, and echo, the refrain amongst front-end devs is: if I had container queries available, 90% of the media queries I write would be container queries. The thought being, you’re usually trying to adjust some particular element’s properties that are tied to something a bit more scoped than the entire browser window.

Ethan Marcotte recently wrote:

I don’t want to suggest that the technical challenges of specifying container queries are in any way easy. But some kind of movement would be deeply appreciated by the entire responsive design community. Speaking just for myself, I know container queries would revolutionize my design practice, and better prepare responsive design for mobile, desktop, tablet—and whatever’s coming next.

Hear hear.

He pointed to some of his own work in which modules that are in extremely different situations that aren’t directly related to the viewport, but more directly related to a parent container.

But now lately, in a wacky surprise twist, there has been a good bit of “hmmmm, perhaps we don’t need these as much as we think we do” going on.

For instance, Dave Rupert, while playing with CSS Grid Layout, found he was able to ditch some media queries entirely:

I refactored a ~50 line Flexbox grid to just ~5 lines of CSS with CSS Grid. … The best part is, we don’t need media queries! This will save a lot of code down the line. In this particular project, we actually have three Flexbox grids with slightly different breakpoints. The auto-fill keyword auto-generates columns when space is available.

See the Pen Flexbox Grid vs. CSS Grid by Dave Rupert (@davatron5000) on CodePen.

Flexbox can do some really fancy dancing with its ability to wrap, its ability to be told if it can grow or not, and how much and to what limits gives us a lot of control without explicit media queries.

Grid gives us even more tools with things like auto layout, minmax(), and keywords like min-content and auto-fill. The fact that you can nest Flex containers and Grid containers any-which-way makes for some powerful possibilities.

For example, see Jonathan Snook playing around (who, self-admittedly, is just starting to wrap his head around these types of layouts) have a lot of success in container-query-like control over some modules.

Paul Robert Lloyd explictly questions the need for container queries:

In my mind, container queries appear to be yesterday’s answer to today’s problems. I’d much rather we use the great new tools we have, and embrace a future that’s finally here.

Even rebuilding Ethan’s example with only a page-layout affecting media query:

See the Pen Rebuilding The Toast’s Recirculation Module by Paul Lloyd (@paulrobertlloyd) on CodePen.

Jeremy Keith filling in as baby bear:

… this is a good well-reasoned post about why container queries might not be the all-healing solution for our responsive design problems. Thing is, I don’t think container queries are trying to be an all-encompassing solution, but rather a very useful solution for one particular class of problem.

So I don’t really see container queries competing with, say, grid layout (any more than grid layout is competing with flexbox), but rather one more tool that would be really useful to have in our arsenal.

Even container queries can’t solve all RWD problems, of course. As Paul said:

The final reason I question the need for container queries is that a change in layout sometimes requires a change in behavior, too. If accomplishing this involves restructuring the DOM, we’re essentially swapping one component for another.

So yes, newfangled layout tools may save us in many situations from needing container queries specifically for layout changes. But layout isn’t the only thing that may need to change in an element depending on the container situation. Ethan responds:

Depending on a module’s placement, height, and width, I might want to change several different aspects of its design. These changes would include, but aren’t limited to:

  1. Visual weight. Depending on where the module’s positioned, I’ll frequently want to change how visually prominent it is. This might include changing its color, its background color, or the size of individual elements within it, all depending on the space allocated to the module.
  2. Typography. Related to that last point, I frequently need to change the typography of an element, based on the size of its container. Grid Layout and flexbox aren’t any help here, sadly; and as much as I love flexible typographyTrent can vouch for me here—the utilities we have to work with there are still very viewport-focused.
  3. Content hierarchy. I often need to change an element’s priority, depending on the size of its container. Maybe I’ll conditionally position an element higher (or lower) to make it more (or less) visible, as the design warrants. In a flexbox-ier layout, I might want to change the order of a given element, or perhaps change the flex-direction of the module—and again, all based on the dimensions of the container.

Brad Frost makes a simple, logical argument:

… having a mechanism that says “if this component lives in a container that’s at least X-wide, make these style changes” feels like it makes sense.

It’s a smidge like responsive images. You can do a lot with srcset and sizes, but there is also when you need to be super explicit about how to behave.

Personally, I’d like to see about 100 different use cases fleshed out. If it turns out some of them can be done sans container queries, awesome, but it still seems highly likely to me that having container queries available to us would be mighty handy.


Container Query Discussion is a post from CSS-Tricks

]]>
https://css-tricks.com/container-query-discussion/feed/
7
253471

Content doesn’t need to delay website launches
http://synd.co/2nEpTs7
https://css-tricks.com/%e2%80%8bcontent-doesnt-need-delay-website-launches/#respond
Thu, 06 Apr 2017 15:19:43 +0000

https://css-tricks.com/?p=253366
<![CDATA[Whether content is late, structured differently to the design or lost in email threads – content always gets the blame for website project delays. Now you can use GatherContent to organize and produce website content without the chaos. 1000s of teams worldwide use GatherContent to implement a structured process for content that helps launch website projects on time.

GatherContent integrates with WordPress, Drupal, Sitecore, Kentico, AEM, Sitefinity, Umbraco, and more!

See how GatherContent can streamline your website content production – …


Content doesn’t need to delay website launches is a post from CSS-Tricks

]]>
<![CDATA[Whether content is late, structured differently to the design or lost in email threads – content always gets the blame for website project delays. Now you can use GatherContent to organize and produce website content without the chaos. 1000s of teams worldwide use GatherContent to implement a structured process for content that helps launch website projects on time.

GatherContent integrates with WordPress, Drupal, Sitecore, Kentico, AEM, Sitefinity, Umbraco, and more!

See how GatherContent can streamline your website content production – try it for your projects with a free 30 day trial!

Here’s some of the internal screens of what it’s like working in there:

Project Overview
Item Editor

Note from Chris: I was so happy to see this sponsorship come through, as we’re big fans of GatherContent at CSS-Tricks. We’ve been using it for years as a tool for (ahem) gathering and collaborating content from sponsors. It’s often a three-way collaboration between us, Syndicate Ads (the folks who help us wrangle sponsors), and the sponsor themselves. GatherContent makes that easy.

Just to be super meta, here’s an example of us working on this exact thing.

Direct Link to ArticlePermalink


Content doesn’t need to delay website launches is a post from CSS-Tricks

]]>
https://css-tricks.com/%e2%80%8bcontent-doesnt-need-delay-website-launches/feed/
0
253366

SEO and Location
https://css-tricks.com/seo-and-location/
https://css-tricks.com/seo-and-location/#comments
Thu, 06 Apr 2017 15:18:34 +0000

https://css-tricks.com/?p=253467
<![CDATA[This is just a baby thought I had about SEO.

I overheard some folks at the gym I go to talking about SEO. It was a part-owner of the gym, talking about an SEO firm they were in contact with to help them with the gym website and reaching more people. A concern all businesses share: how do we sell to more people.

In the context of a gym, sales will be limited to a pretty narrow geographic region. With …


SEO and Location is a post from CSS-Tricks

]]>
<![CDATA[This is just a baby thought I had about SEO.

I overheard some folks at the gym I go to talking about SEO. It was a part-owner of the gym, talking about an SEO firm they were in contact with to help them with the gym website and reaching more people. A concern all businesses share: how do we sell to more people.

In the context of a gym, sales will be limited to a pretty narrow geographic region. With rare exception, people don’t drive clear across town to go to the gym, because gyms are largely a commodity and dotted all over cities. So the available market is humans in this narrow geographic region who want to join a gym.

Two more facts:

  1. This gym is named: [name of neighborhood] fitness.
  2. It comes up very easily in all manner of web and map searches.

I can’t imagine what an SEO company can do for this gym, aside from a general lookover of the site for best practices and light advice.

SEO is all about search, and this gym already comes up in the relevant searches. There is no magic to work here. Search engines want to help you find what you are looking for, and they are doing their jobs well here already. Some other kinds of marketing and advertising might help get more folks in the door, but search is fine.

If search wasn’t fine, then sure, it seems warranted to try and figure out why and get the business showing up for the relevant searches.

I also overheard what the SEO company wanted: $2,500/month.

It’s not surprising to me why so many web folks roll their eyes and sneer at SEO consultants and agencies. That seems highly predatory.

$2,500 could go a long way in local advertising, actually reaching people in different ways.


SEO and Location is a post from CSS-Tricks

]]>
https://css-tricks.com/seo-and-location/feed/
5
253467

Some Conference News
https://css-tricks.com/some-conference-news/
https://css-tricks.com/some-conference-news/#respond
Thu, 06 Apr 2017 13:42:03 +0000

https://css-tricks.com/?p=253464
<![CDATA[News about some upcoming conferences, like Clarity, CodeLand, a Grid Workshop,

Maker Series, and upcoming An Event Apart shows.


Some Conference News is a post from CSS-Tricks

]]>
<![CDATA[Last year I got to MC the first ever Clarity, "A Design Systems Conference", organized by Jina in San Francisco. It’s back! Coming November 28th-30th, 2017.


Saron Yitbarek is organizing the first CodeNewbie conference, CodeLand, coming up real quick here on April 21st-22nd in New York.

I got to be on the CodeNewbie podcast a while back, and we had her on ShopTalk.


Also coming up quick, Timothy Smith is running an inexpensive online workshop called “Let’s Learn CSS Grid” coming up April 21st, 2017.


I’ve just finished giving a talk and all-day session at An Event Apart Seattle, but never fear! If you’d like to catch me speak, I’ll be at the next An Event Apart in Boston, coming up May 15th-17th. Also in Chicago August 28th-30th, 2017 where I’ll also be giving the all-day session on being a front-end developer.

If you’d like to catch that all-day session, I’m also going to be giving it August 7th in Dayton, Ohio at the Build Right: Maker Series.


If you’re researching web conferences around the world and want to see what’s out there, don’t forget our guide!


Some Conference News is a post from CSS-Tricks

]]>
https://css-tricks.com/some-conference-news/feed/
0
253464

Little Stuff about Markdown I Always Forget and have to Google
https://css-tricks.com/little-stuff-markdown-always-forget-google/
https://css-tricks.com/little-stuff-markdown-always-forget-google/#comments
Wed, 05 Apr 2017 13:50:51 +0000

https://css-tricks.com/?p=253430
<![CDATA[This is mostly for me. These are the little things that sometimes confuse me about Markdown and I find myself having to search the web for. So I'll write them down. Blogging as memory extension.

Know that your mileage may vary on this stuff, as there are many varietals of Markdown.

markdown=”1″

There is no concept of a

in Markdown syntax (or most other structural HTML elements), except that Markdown supports HTML so you can just use a …


Little Stuff about Markdown I Always Forget and have to Google is a post from CSS-Tricks

]]>
<![CDATA[This is mostly for me. These are the little things that sometimes confuse me about Markdown and I find myself having to search the web for. So I'll write them down. Blogging as memory extension.

Know that your mileage may vary on this stuff, as there are many varietals of Markdown.

markdown=”1″

There is no concept of a

in Markdown syntax (or most other structural HTML elements), except that Markdown supports HTML so you can just use a

if you want to. But as soon as you do, nothing nested inside of it can be Markdown.

### Header



1. Nope 1. Not 1. Happening

Except it can! In many (most?) varietals of Markdown, you can put

on the element and it will allow Markdown inside of it.

### Header



1. All 1. Fixed 1. Up

Multiple paragraph lists and blockquotes

If a list item need multiple paragraphs in it, you can’t just break multiple lines and keep going. The next paragraph needs to be indented for it to be considered part of the same list item. Otherwise the list ends and new one starts.

1. one paragraph

    more for 1st list item :)

1. another paragraph

Blockquotes are similar:

> First bit.
> Second bit.

There will be no line break there. Those two bits will be inside the same inside the

. To make them multiple paragraphs, you’ll need a blank line in between.

> First bit.

> Second bit.

If you wanted them to be entirely separate

s, without any other text in between, I’m not sure what’d you do.

Escaping characters

Certain characters have meaning in markdown, like how *asterisks* make text italic. But what if you want to actually display an asterisk? You escape it with a backslash, like \*.

You can even escape the backslash itself, meaning \\ is \.

ID’s

Markdown supports HTML, so if you need any special attributes on elements, you can just use HTML. But it’s nice to not have to.

Different varietals of Markdown handle it in different ways.

A somewhat common way is to allow them on headers like this:

### Custom IDs {#custom-id}

Some varietals simply add an ID on all headings for you automatically.

This is also doable client side.

Images

It’s the same as the link syntax [link text](url) except it starts with a bang.

![alt text](http://example.com/image.jpg)

Slightly trickier still is nesting it to be a link:

[![alt text](image.jpg)](https://css-tricks.com)

Languages on Code Fences

The language comes right after the first set of backticks.

```css
body {
  background: red;
}
```

Tables

You basically draw them like ASCII art. Note the dashes to denote the header row, and the colons for alignment:

| header | header | header |
|--------|:------:|-------:|
| a      |    b   |      c |
| 1      |    2   |      3 |
| foo    |   bar  |    baz |

I guess I’m not alone

Here’s quite a thread of what other folks forget.


Little Stuff about Markdown I Always Forget and have to Google is a post from CSS-Tricks

]]>
https://css-tricks.com/little-stuff-markdown-always-forget-google/feed/
10
253430

Lazy Loading Gravatars in WordPress
https://css-tricks.com/lazy-loading-gravatars-wordpress/
https://css-tricks.com/lazy-loading-gravatars-wordpress/#comments
Tue, 04 Apr 2017 16:59:55 +0000

https://css-tricks.com/?p=253401
<![CDATA[Most WordPress themes show user Gravatars in the comment threads. It’s a way of showing an image with the user, as associated by the email address used. It’s a nice touch, and almost an expected design pattern these days.

Every one of those gravatars is an individual HTTP request though, like any other image. A comment thread with 50 comments means 50 HTTP requests, and they aren’t always particularly tiny files. Yeesh.

Let’s lazy load them.

The Concept

Lazy loading …


Lazy Loading Gravatars in WordPress is a post from CSS-Tricks

]]>
<![CDATA[Most WordPress themes show user Gravatars in the comment threads. It’s a way of showing an image with the user, as associated by the email address used. It’s a nice touch, and almost an expected design pattern these days.

Every one of those gravatars is an individual HTTP request though, like any other image. A comment thread with 50 comments means 50 HTTP requests, and they aren’t always particularly tiny files. Yeesh.

Let’s lazy load them.

The Concept

Lazy loading is the idea that you don’t even request the image at all (no HTTP request) unless the image is visible. Meaning that, through JavaScript, we’ve determined the image is visible.

Lazy loading means not loading those two images that are outside the browser window, until they become inside the browser window.

In order to stop those HTTP requests for not-yet-seen images, we need to get our hands directly on the markup. If there is an in the HTML, there is essentially no way to stop the browser from downloading that image as soon as it possibly can, seen or unseen. So, we need to remove that src, and put it back when we’re ready.

Woah, There

It’s worth a pause here because we’ve entered some murky territory.

By removing the src of these images, and only ever putting it back with JavaScript, we’ve decided that we’re willing to ship slightly invalid HTML and rely 100% on a script downloading and executing for these images to ever be seen.

I’m OK with that. Mostly because gravatars are just an enhancement anyway. It ain’t no big deal if they never show up. I’m not a hardliner most JavaScript debates, but this seems like a particularly clear case where we can lean on JavaScript without worry.

Altering the HTML

This is the change we’d be making:

 

Although a missing src on the  is technically invalid HTML. It almost certainly doesn't really matter in that it won't affect how anything works. If the invalid HTML bugs, you could always toss a super minimal blank GIF data URL in there, like:

Using width and height attributes is probably a good idea too, to maintain layout and avoid reflow if and when the images to load.

Altering the HTML... in WordPress

But how do you change the HTML that WordPress spits out as part of a comment thread? Comments are slightly unusual in WordPress in that WordPress core gives you the HTML, it isn't part of your theme like most of the other HTML is.

Likely, in your `comments.php` file, you'll see this function:

Which spits out a pile of

  • 's with your entire comment thread. Not a lot of opportunity there to be fiddling with the output of images. Except, we can! We can list a callback function in there: 

    That callback is the name of a function we can toss in our `functions.php` file. Here's an example of that function, which must return a

  • function csstricks_comment($comment, $args, $depth) {
    
      $GLOBALS['comment'] = $comment; ?>
    
    
    
  • ">

    User Avatar 160)); ?>">

    <!--?php # phantom

  • ?>

    <!--?php }

  • That's very simplified, but you can see what we've done. We replaced the src with the blank GIF, we've added a class name we'll ultimately use in JavaScript to do the lazy loading, we've added a data-src to the actual gravatar, and we're using width and height attributes for placeholding. Here's my actual complete callback live right now on CSS-Tricks.

    If we shipped this right now, sans any JavaScript work, we'd still have a perfectly functional comment thread, just with images that never load.

    Now We're Ready to Lazyload

    The hard part is over. We're perfectly set up to do lazyloading now. If we were to write a script, it would be like:

    1. Figure out the visible area of the browser window
    2. Figure out the position on the page of every image with class .lazyload-gravatar
    3. If any of those images are in the visible area, flop out the src with the value from data-src
    4. If the visible area of the browser window changes in any way, re-evaluate the above

    We could set about writing that ourselves. And we could do it! But, and I'm sure you're not surprised here, it's a bit tricky and nuanced. Cross-browser concerns, performance concerns, does-it-work-on-mobile concerns, to name a few. This is the kind of thing I'm happy to lean on other's work for, rather than roll myself.

    Again, no surprise, there are loads of options to pick from. In my case, I'm happily using jQuery on CSS-Tricks, and I picked a jQuery-based on that looked pretty good to me:

    The API is as simple as can be. After bundled up the lib with the rest of the libs I'm using, I just call:

    $('.lazyload-gravatar').Lazy();

    Look how nicely it works!

    That's an awful lot of saved HTTP requests and awful good for performance.

    Makes you wish web standards and browsers would get together on this and make it a native feature.


    Lazy Loading Gravatars in WordPress is a post from CSS-Tricks

    ]]-->
    https://css-tricks.com/lazy-loading-gravatars-wordpress/feed/
    10
    253401

    How To Make Guides (Collections of Content) in WordPress
    https://css-tricks.com/make-guides-collections-content-wordpress/
    https://css-tricks.com/make-guides-collections-content-wordpress/#comments
    Mon, 03 Apr 2017 15:32:56 +0000

    https://css-tricks.com/?p=253363
    <![CDATA[A blog post can be anything you want. You could easily write one that links up a bunch of articles on your site. Titles, summaries, links... all hand-crafted HTML. A "guide", as it were. It will likely be appreciated by your readers, I find, especially when you're linking up old evergreen content that is still relevant and useful today.

    But let's say you want to programmatically create these "guides". That might make them faster to create, easier to maintain, and …


    How To Make Guides (Collections of Content) in WordPress is a post from CSS-Tricks

    ]]>
    <![CDATA[A blog post can be anything you want. You could easily write one that links up a bunch of articles on your site. Titles, summaries, links... all hand-crafted HTML. A "guide", as it were. It will likely be appreciated by your readers, I find, especially when you're linking up old evergreen content that is still relevant and useful today.

    But let's say you want to programmatically create these "guides". That might make them faster to create, easier to maintain, and give you a nice level of control over them. Let's look at a way to do that.

    Guides on CSS-Tricks

    I'm writing about this because guides are something we've just started to do here on CSS-Tricks. For example, I wanted to make a guide of our content that is well suited for folks just starting out, so I made Our Guide To Just Starting Out with CSS & HTML.

    That wasn't built by hand, it was built by programmatically attaching a variety of content to a Custom Post Type we created just for Guides.

    Programmatically Attaching Posts to Posts

    You know how you can put images into blog posts? But in WordPress, there is also a concept of a featured image, which is one specific programmatically attached image for that post.

    That image is programatically attached to this Post.

    Enabling that feature in WordPress is like:

    add_theme_support('post-thumbnails', array('post', 'page', 'whatever'));

    But we're talking associating Posts with Posts not Images to Posts. There is no built-in WordPress way of doing that, so we'll reach for plugins.

    CMB2 and Friends

    CMB2 (i.e. the second version of "Custom Meta Boxes") is a free, open source plugin for adding better UI and functionality around custom fields. If you're familiar with Advanced Custom Fields, it's a bit like that, only I guess entirely free and a bit more modular.

    With that installed, now you can install (I guess we'll call them sub-plugins?) that make CMB2 do stuff. The one we're after is CMB2 Attached Posts Field which has the explicit job of attaching Posts to Posts (or really, post type to any post type).

    It gives you this two-column UI on post types you activate it for:

    Move anything from the left to right, and it's now programatically attached. This is exactly what we're after. Now we can hand select, and hand order, any type of post to attach to any other.

    Configuring Things

    Before you get to the UI you can see above, you not only need to install and activate those two plugins, but also tell CMB2 to create the custom meta boxes and apply them to the types of posts you want.

    In our case, our Guides are a custom post type. That's easy enough to enable:

    register_post_type( 'guides',
      array(
        'labels'        => array(
          'name'          => __( 'Guides' ),
          'singular_name' => __( 'Guide' ),
          'add_new'       => __( 'Add Guide' ),
          'add_new_item'  => __( 'Add New Guide' ),
          'edit_item'     => __( 'Edit Guide' ),
        ),
        'public'      => true,
        'has_archive' => true,
        'rewrite'     => array( 'slug' => 'guides' ),
        'supports'    => array( 'title', 'editor', 'thumbnail', 'excerpt' )
      )
    );

    Then we apply this new custom meta box only to that custom post type (so we don't have to see it everywhere):

    $cmb = new_cmb2_box( array(
      'id'            => 'guide_metabox',
      'title'         => __( 'The Guide Metabox', 'cmb2' ),
      'object_types'  => array( 'guides', ), // Post type
      'context'       => 'normal',
      'priority'      => 'high',
      'show_names'    => true, // Show field names on the left
      // 'cmb_styles' => false, // false to disable the CMB stylesheet
      // 'closed'     => true, // Keep the metabox closed by default
    ) );
    
    // Regular text field
    $cmb->add_field( array(
      'name'       => __( 'Things for the Guide', 'cmb2' ),
      'id'         => 'attached_cmb2_attached_posts',
      'type'       => 'custom_attached_posts',
      'show_on_cb' => 'cmb2_hide_if_no_cats',
      'options' => array(
        'show_thumbnails' => true, // Show thumbnails on the left
        'filter_boxes'    => true, // Show a text box for filtering the results
        'query_args'      => array(
          // 'posts_per_page' => 2,
          'post_type' => array('post', 'page')
        ), // override the get_posts args
      ),
    ) );

    We nestle all this code nicely into a functionality plugin, rather than a `functions.php` file, so that changing themes has no bearing on this content.

    A Template for Guides

    Now that a custom post type exists for our guides, adding a file called `single-guides.php` into our active theme is enough to make that the file that renders for like `/guide/example/`.

    In that file, we do whatever normal template-y stuff we'd do on any other template file (e.g. `page.php`, but also loop through all these posts we've attached!

    
    
      
    
    

    All in all, not that much to it!

    It feels great to have some kind of mechanism for surfacing evergreen content like this. That can be quite a challenge for sites with a huge amount of content!


    High five to Rebekah Monson, whom I ripped this idea off of, who uses this to build guides on The New Tropic, like these neighborhood guides.


    How To Make Guides (Collections of Content) in WordPress is a post from CSS-Tricks

    ]]>
    https://css-tricks.com/make-guides-collections-content-wordpress/feed/
    8
    253363

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s