By Harry Roberts
Harry Roberts is an independent consultant web performance engineer. He helps companies of all shapes and sizes find and fix site speed issues.
Written by Harry Roberts on CSS Wizardry.
Ack is a powerful and very user-friendly alternative
to grep. Designed for programmers, it’s purpose-built to run searches over
source code. By default it will ignore your .git
or .svn
directories, and
you can tell it which types of files you’d like it to search in. For example:
$ ack --html "foo"
…will search for the string foo
only in your HTML files.
$ ack --html --js --css "bar"
…will search for the string bar
in your HTML, JS, and CSS files. Neat, huh?
Get into the habit of always wrapping your search terms in quotes. Without this, we run the risk of our search terms and regexes being interpreted as command line arguments.
I use Ack as part of auditing a project, or when trying to find my way around a larger codebase. It’s also pretty useful for tracking down bugs and oddities. In this short post, we’ll look at a small number of ways CSS developers can make use of Ack in their workflow.
If you’re on a Mac, you can install Ack using Homebrew:
$ brew install ack
As simple as that!
For other operating systems, check the official installation guide.
To use Ack, you’ll probably want to cd
into the root of your project, or the
root of your CSS directory. Ack searches all files on and below your current
location. Here’s what my terminal looks like whilst writing this article:
harryroberts in ~/Sites/csswizardry.com on (master)
» ack <search term>
.ackrc
Ack is extensible and configurable, making use of its own .ackrc
dotfile. This
lives in your home directory, alongside your .vimrc
, .bashrc
, etc. Here are
some things that I added to mine that you’ll probably like as well:
--ignore-directory=is:node_modules
--ignore-directory=is:bower_components
--type-set=sass:ext:scss,sass
--type-set=markdown:ext:md,markdown
Here I’m telling Ack to exclude my node_modules
and bower_components
directories, as well as adding Markdown and Sass as new filetypes. This means
that if I run:
$ ack --sass "foo"
…Ack will search every .scss
and .sass
file in my project. To see what
filetypes Ack will search, run:
$ ack --help-types
If you think something is missing, add it to your .ackrc
.
To use Ack, you will need to know a little bit of regex. Don’t worry though: my regex is pretty weak and even I can still manage.
$ ack --css "\d*\.\d*px"
We don’t want to have any decimal places in any of our pixel values (e.g.
7.5px
), so let’s search for those:
\d*
will match zero or more (*
) \d
igits. The reason I’m looking for zero
or more is because I want to find both .5px
or 11.2px
.\.
will match a literal full-stop/period character.\d*
is the same as before. This means I will find both 97.856px
, or
52.px
(which is actually just an error).px
will match the literal string px
: I don’t want to look for ems or rems
or percentages because they accept float values.See the demo.
We definitely shouldn’t be using IDs in CSS, so let’s look for them:
$ ack --css -i "#[-_a-z][-_a-z0-9]*(?=[^}]*\{)"
Firstly, notice the -i
flag. This tells Ack to run our regexes case
insensitively.
This pretty complex regex does a few things:
#
finds a literal hash (#
) symbol.[-_a-z]
finds a single hyphen (-
), underscore (_
), or case insensitive
a-z
, denoting a valid start to an ID.[-_a-z0-9]*
does almost exactly the same as above, except this time we’re
looking for zero or more (*
) characters, and for digits as well (0-9
).
We’re doing this separately from the previous lookup because IDs can’t start
with numbers.(?=[^}]*\{)
is running a positive lookahead, just checking that we encounter
an opening curly brace (\{
) next, and not a closing one ([^}]
).This means we will find IDs, but not hex values.
N.B. Because of Sass’ nesting abilities, nested code containing hex values becomes a false positive. As such, only run this regex over your compiled CSS. Please refer to the demo.
$ ack --css -i "background:\s*#[a-f0-9]*;"
I recently wrote about how I consider background shorthand syntax an anti-pattern, so we should probably look for that whilst we’re here.
background:
finds the literal string background followed by a colon (:
).\s*
matches zero or more units of whitespace between the colon and the
beginning of a hex value.#
is the literal hash symbol (#
), the beginning of a hex value.[a-f0-9]*
is a valid hex value (e.g. #f00
, #BADA55
). Setting the -i
flag means that our regex is now case insensitive.;
matches the literal semi-colon character (;
) which denotes the
termination of the declaration.See the demo.
$ ack --css "\b0(px|r?em)"
This is a little pedantic of me, but putting a unit (e.g. px
) on a zero (0
)
is redundant: zero pixels is the same distance as zero lightyears. Let’s look
for them.
\b
looks for a word boundary. This means we’re looking for zeroes at the
start of a string (i.e. 0px
) and not midway through one (e.g. 210px
).0
is looking for the literal zero character (0
).(px|r?em)
looks for the literal strings px
or rem
or em
.r?em
makes the r
optional, so we can match either rem
or em
at the
same time.See the demo.
Those are just a few of the most common things I search CSS files for as part of an audit, but of course Ack can help me find all manner of things, from finding specific classes, properties, selectors, or values, right the way to finding errors and bugs.
Harry Roberts is an independent consultant web performance engineer. He helps companies of all shapes and sizes find and fix site speed issues.
Hi there, I’m Harry Roberts. I am an award-winning Consultant Web Performance Engineer, designer, developer, writer, and speaker from the UK. I write, Tweet, speak, and share code about measuring and improving site-speed. You should hire me.
You can now find me on Mastodon.
I am available for hire to consult, advise, and develop with passionate product teams across the globe.
I specialise in large, product-based projects where performance, scalability, and maintainability are paramount.