CSS Selectors

I can never remember the syntax for this stuff.

Select by attribute presence

<p>This paragraph has a <a href='#'>link</a> in it.</p>  
[href] { background : cyan; }

This paragraph has a link in it.


Combine with element

<p title='wigwam'>This paragraph has a title attribute.</p>  
p[title] { background : cyan; }  

This paragraph has a title attribute.

Putting a space between p and [title] would specify the children of paragraph with title attributes.

<p>This paragraph has a couple of <span title='wigwam'>spans</span> with a <span title='wigwam'>title</span> attributes.</p>  
p [title] { background : cyan; }  

This paragraph has a couple of spans with a title attributes.


Target an attribute and its contents

The content of an attribute can also be specified by having the attribute equal something

<p>This paragraph has a couple of <span title='t1'>spans</span> with different <span  
title='t2'>title</span> attributes.</p>  
[title="t1"] { background : cyan; }
[title=t2] { background : yellow; }

This paragraph has a couple of spans with different title attributes.


Target a specific word in the attribute

Using the tilde (~) it is possible to target by a single string in a space separated list.

<p>This paragraph has a couple of <span title='one two three'>spans</span> with different <span title='one three four'>title</span> attributes.</p>  
[title~="one"] { font-weight : bold; }<br/>
[title~="two"] { background : cyan; }

This paragraph has a couple of spans with different title attributes.

It is also possible to target a substring at the end using the dollar ($) sign.

<p>This paragraph has a couple of <span title='twotone'>spans</span> with different <span title='donedown'>title</span> attributes.</p>  
span[title$="one"] { background : cyan; }  

This paragraph has a couple of spans with different title attributes.

To target a substring at the beginning use the caret (^) sign.

<p>This paragraph has a couple of <span title='twotone'>spans</span> with different <span title='onedown'>title</span> attributes.</p>  
span[title^="one"] { background : cyan; }  

This paragraph has a couple of spans with different title attributes.

It is also possible to target an exact match followed by anything separated with a dash using the pipe (|) symbol.

<p>This paragraph has a couple of <span title='one-up'>spans</span> with different <span title='one-down'>title</span> attributes.</p>  
span[title|="one"] { background : cyan; }  

This paragraph has a couple of spans with different title attributes.

Lastly we can do a full text search using the asterisk (*)

<p>This paragraph has a couple of <span title='donedown'>spans</span> with different <span title='doneup'>title</span> attributes.</p>  
span[title*="one"] { background : cyan; }  

This paragraph has a couple of spans with different title attributes.


Attribute stacking

Attribute selection can also be stacked to give even finer control of selection.

<p>This paragraph has a couple of <span class='onetwothree' title='onetwothree'>spans</span> with different <span class='twothreefour' title='onetwothree'>title</span> attributes.</p>  
span[class~='one'][title*="two"] { background : cyan; }  

This paragraph has a couple of spans with different title attributes.


Outputting attributes

An element's attribute can also be used in pseudo-elements for output.

<p>This paragraph has a <a href='https://lewiswalsh.com'>link</a> with a dynamically printed href.</p>  
a:after { content: " (" attr(href) ")"; }  

This paragraph has a link with a dynamically printed href.


Case sensitivity

By default all CSS attribute selectors are case-sensitive. To make the selection case-insensitive add an 'i' to the end of the selection.

[title*="one" i] { }

GeoIP blocking and redirecting on Apache

Recently I was asked to configure a WordPress install to block any traffic from Russia, and redirect any traffic from the USA to another US-centric site.

First thing to do is install mod-geoip for Apache (in my case on Ubuntu):

sudo apt install libapache2-mod-geoip  

Next uncomment the GeoIP database in the GeoIP conf file (/etc/apache2/mods-available/geoip.conf):

<IfModule mod_geoip.c>  
  GeoIPEnable On
  GeoIPDBFile /usr/share/GeoIP/GeoIP.dat
</IfModule>  

Restart Apache:

sudo systemctl restart apache2  

With GeoIP enabled we can apply our block and redirect in .htaccess

GeoIPEnable On

# deny for Russia
SetEnvIf GEOIP_COUNTRY_CODE RU DenyCountry

# redirect for USA
RewriteEngine on  
RewriteCond %{ENV:GEOIP_COUNTRY_CODE} ^(US)$  
RewriteRule ^(.*)$ https://usa-site.com/$1 [L]  

A list of ISO Alpha-2 country codes can be found on WikiPedia, and many other places online.

Javascript Media Queries

Javascript media queries used to be a pain in the butt. I won't go in to why because thanks to window.matchMedia it's now very easy.

window.matchmedia has a matches property which returns a boolean value, so to run it once just use it something like and if statement:

if(window.matchMedia("(min-width: 500px)").matches) {  
  /* the viewport is at least 500 pixels wide */
} else {
  /* the viewport is less than 500 pixels wide */
}

It's also possible to add a listener to call a function to run some code whenever the query return value changes:

if(matchMedia){ // Only run if matchMedia is supported  
  const media_query = window.matchMedia("(max-width : 500px)"); // Create media query
  media_query.addListener(widthChange); // Optional listener with function to run
  widthChange(media_query); // Initial run
}

function widthChange(media_query){  
  if(media_query.matches){ // If the media query resolves true
    // window width is under 500px wide
    console.log('Under');
  } else {
    // window width is more than 500px wide
    console.log('Over');
  }
}

Neat Vanilla JS on HackerNews

I recently saw this video by Gordon Zhu highlighting the small but extraodinarily clever JavaScript on the Hacker News website.

I felt it would help me if I simplified it and broke down the steps for future reference. I'm using Paul Buchheit's code verbatim, I hope he doesn't mind, full credit to him.

What does this achieve?

This code is called when an anchor (a link) is clicked to vote up an item on Hacker News. It casts the vote and hides the vote up link so it can't be clicked again.

HTML

The markup for this is REALLY simple. It's a perfect example of progressive enhancement. The full URL is present in the HREF so if JavaScript is turned off the onclick is never called but the vote is still cast.

<a id="up_11659026" href="vote?for=11659026&dir=up" onclick="return vote(this);">Vote Up</a>  

JavaScript

No JQuery here! This is concise and elegant vanilla JS. The only JS on the site is following two functions, with the latter calling the former.

function hide(id){  
  var el = document.getElementById(id);
  if (el) { el.style.visibility = 'hidden'; }
}
function vote(node){  
  var v = node.id.split(/_/);
  var item = v[1];
  hide('up_'   + item);
  hide('down_' + item);
  var ping = new Image();
  ping.src = node.href;
  return false;
}

How does it work

  1. When the link is clicked the vote() function is called with the anchor (<a>) element passed as this
  2. The id, up_11659026, is split at the underscore and the parts passed to an array, v
  3. A new var, item, is given the value at v[1], in this case 11659026
  4. Two calls are made to the hide() function, one with the value up_11659026, and one with the value down_11659026
  5. The hide() function looks for an element with the passed id, if it finds it, the visibility of the element is set to hidden
  6. A var is created, ping, and is an instance of JavaScript's Image object.
  7. By setting the src of ping to the href of the clicked element, the URL is called (in this case a vote is cast by the back-end)
  8. Nothing is returned or rendered as it's unnecessary.
  9. We return false to stop the URL being followed by the browser
  10. If JavaScript is turned off in the browser, the URL is followed when clicked and the same outcome occurs.

Key only SSH

To cut back on the hacking attempts and make things just that little bit more secure, it's a good idea to disable the use of passwords to login via SSH.

Of course you'll need a way to access it so make sure you're public key is in your ~/.ssh/authorized_keys file.

To disable the use of passwords with SSH edit the sshd_config config file using something like nano. You'll need to run this as sudo.

sudo nano /etc/ssh/ssh_config  

Find the following lines and change them, or add them if they're missing:

RSAAuthentication yes  
PubkeyAuthentication yes  
ChallengeResponseAuthentication no  
PasswordAuthentication no  
UsePAM no  

One caveat here. I found on Ubuntu 12.04 that when I turn off UsePAM the banner I usually see when connecting with SSH is not shown.

To fix this I uncommented and ammended the line which reads #Banner /etc/issue.net:

Banner /etc/motd  

Of course you'll need to restart sshd, depending on what service management system you use, enter the following:

sudo service ssh restart  
or  
sudo /etc/init.d/sshd restart  

Important Don't lose your private keys which match the public keys you've used, or you'll never get back in!