My experience contributing to Servo

Some months ago a colleague introduced me to Rust and to the Servo project. It’s a web browser engine led by Mozilla, and its code is available on GitHub and is open to contributions.

Working on Servo was attractive to me from the start for several reasons:

  • It’s written in Rust, and Rust has an exciting community, it’s low level and modern, it’s not shackled in any way by existing legacy code nor by industry requirements, and it just seemed like the perfect thing to help me quench my learning thirst.
  • Servo is a web browser engine, and working for a web browser engine as a web developer feels like working on the biggest possible project, on the foundation on which everything I’d ever done took place.
  • Servo has an enormous amount of issues you’re welcome to take. Some of these may seem extremely cryptic and complicated for someone new, but others are extremely trivial. You’ll be sure to find the full gradient of difficulties in Servo issues, and there’s even Servo Starters, which uses GitHub labels to show issues that are Good first PRs.

Let’s talk about what actually working on the project feels like.

Finding an issue

First, you’ll need to find an issue you find interesting. Helpful labels are E-easy, Good first PR, and C-assigned. You can filter for issues that haven’t been assigned to anyone yet by searching with a negative prefix: -label:C-assigned. Here’s a good filter to start with:

is:issue is:open label:E-easy -label:C-assigned

Do not be discouraged by issues which don’t have the E-easy label on them. In my experience, an E-easy task could end up being a bit more complicated anyway: the line between easy and difficult is blurry and you’ll only find out what you’re facing once you start working on it.

Also, don’t forget Servo Starters.

Working on your task

Once you’ve found the issue you want to work on, make sure to leave a comment saying you’re working on it so there’s no two people implementing the same thing separately.

Compiling Servo is understandably slow: it’s a huge project. Your first run will likely take between thirty minutes and one hour depending on your machine and connection, and after some re-runs and testing you’ll find yourself with a 15GB directory.

Servo has its own tool, mach, which you can use to build for development (./mach build -d), for release (./mach build -r), and to do many other things. When you submit your pull request, it must pass some CI tests which you can try locally to save time:

If all of those pass, you’re almost safe to think it will pass the first CI tests. Check out the complete .travis.yml file to see the rest. Of course, even if your changes don’t pass the tests, you can submit your pull request and expect help from the Servo project members.

Submitting a pull request

What you need to do to submit a pull request is carefully explained in Servo’s Wiki Page about GitHub workflow. Once you submit your pull request, you’ll be promptly greeted by a dog. You won’t need to talk to bors-servo but Servo organization members can request CI retries by mentioning @bors-servo.

The review process and regression tests

If needed, you’re guaranteed to receive extensive help from the project maintainers. In fact, in some cases, I’m quite sure any of the Servo organization members could have solved the problem I was facing with less effort than it took to help me. Here’s some live proof. The help I receive when working on Servo makes for an invaluable learning opportunity and it makes contributing to the project all the more enjoyable. Do not be afraid to ask any doubts, and always do your research on the topic: if you study it enough, you’ll be able to discuss with others and learn even more.

Once your pull request is all green, you can request review by commenting r?. The time until somebody reviews your PR ranges between minutes and a day or two. Somebody will automatically be assigned to the pull request depending on the code area you’re working on. Servo organization members can request a full CI run by commenting @bors-servo try. This will trigger the rest of the CI suites, and the most important one is the Web Platform Tests. It’s a regression test suite used for Firefox a cross-browser regression test suite run for Firefox and (at least in part) by the Chrome, Edge and Safari teams (thanks for the correction jgraham). Many of the tests that run on the suite for Servo come directly from the WPT, but you can also write your own new tests, modify existing ones or modify the expectations for existing test results. Many tests are expected to fail for Servo, and you can also submit a pull request to fix those failures. Of my four pull requests to Servo, two of them have caused failures on the WPT suite and most of the work related to the issue went on fixing and improving the tests.

Running the full test suite takes a long time on CI. Usually around one hour. If a regression test fails live and you’re working on a fix, you can always run the test locally to avoid running the full suite online again. First, make a development build with ./mach build -d and then run the specific test with ./mach test-wpt [path-to-test]. Unexpected test results, such as PASS, expected FAIL will also make the CI suite fail: you’ll need to update the test expectations by modifying the corresponding .ini file. On the guide I linked above there’s all the information you need on how to work with the WPT suite.

Resources to help you figure out how to solve an issue

Of course, this is highly dependent on what type of issue you picked. But in general, the most important resource is documentation. Reading the HTML Living Standard is a great way to help you find the right way to solve a problem. Usually, all the problems are already solved and their solution is in the spec. You’re just writing a different explanation of their solutions… in Rust. Quoting Kevlin Henney:

The act of describing a program in unambiguous detail and the act of programming are one and the same.

You can also find a huge amount of valuable information in the Mozilla Developer Network. Pretty much the same as the spec, but with a lot of examples, and a lot more verbosity. Do not make the same mistake I did and skim through the examples trying to find the exact line that will solve your problem: reading everything thoroughly is what will help you understand the issue best.

If armed with a powerful enough tool, you’ll be able to document your way out of your issue by just reading the source code and searching inside of it. I know all editors have project search functionality but this is a huge project. As of commit b1d7b6bfcf, the Servo repository has a whopping 6,517,647 lines of code (that’s six and a half million). I used loc to count those. So use something fast like ripgrep: it’ll make your life a lot easier.

In the end, you’ll receive the most help from the project maintainers: just ask them. It’s an extremely fun process.

If you think I’ve missed a great resource, please comment below and I’ll be sure to include it in this post, and use it on my own as well.

Conclusion

Working on Servo is one of my main sources of learning nowadays and I’ll keep on trying to find issues I can tackle. The tasks I’ve carried out for now have ranged from a two line change dependency removal to properly setting the origin of fetch requests. The fetch API issue took me almost three months to get merged, mostly because of my lack of understanding of the project. But the project maintainers proved to be exceptionally helpful and pleasant to work with. They also never tried to rush a solution and always “followed” (and this should read “accommodated to” or “slowed down to”) my pace.

I encourage everyone reading this to check out the project and consider contributing to it. The time you spend working on a project like this is extremely valuable to you as a web developer, and in the end you can feel proud of helping build something on which your applications and websites will probably run in the future.

Why won't my text overflow? Where's my ellipsis!?

The text-overflow property is a PITA to deal with because on its own, it won’t force text to overflow. Say what? Its name IS text overflow. Anyway, what it actually does is to define the behavior of a text node if it overflows. The job of actually making it overflow is yours and only yours.

I present to you a checklist that should once and for all truncate that stubborn span and print some beautiful ellipses at the end of your one-liners.

In the checklist, I’ll be using the word “container”. So let’s define it first, just for this post: the “container” I’m talking about is the immmediate parent of the element that contains the text node you want to truncate. For example:

<div> <!-- This div is the container -->
  <span>I will NOT truncate. Nononononono, no!</span> <!-- Let's call this one "stubborn child" -->
</div>

Is your container NOT a flex container? Checklist A is your friend. Is your container a flex container? Checklist B is for you.

Checklist A: for non-flex containers

  1. Is the container a block-level element?
  2. Does the container have a computed size determined by your CSS, or does it inherit one?
  3. Did you add the white-space: nowrap; property to the container?
  4. Did you add the overflow: hidden; property to the container?
  5. Did you add the text-overflow: ellipsis; property to the container? (duh)

Checklist B: for flex containers

  1. Does the container have a computed size determined by your CSS, or does it inherit one?
  2. Does the child also have a computed size determined by your CSS, or does it inherit one?
  3. Did you add the white-space: nowrap; property to the child?
  4. Did you add the overflow: hidden; property to the child?
  5. Did you add the text-overflow: ellipsis; property to the child? (duh)

Hope that helped. Here’s some nice documentation from MDN about the text-overflow property which is well worth the read.

CSS features that Firefox supports but Chrome doesn't

This is a short list of CSS features that work on Firefox but not yet on Chrome. In particular, features that would be really cool to use in production if the other major browsers supported them. Maybe you didn’t know about some of these. Hopefully, I’ll get you informed on them. I’ll update this when the glorious day comes in which we are able to use these without polyfills or any other kind of external libraries.

Scroll snap points

Scroll snap points, in case you haven’t heard of them yet, are a way of introducing precision while scrolling. They’re especially useful for touch devices. Imagine a gallery of images arranged horizontally: a user on a tablet might swipe upwards to continue towards the next image, but the browser scrolls wildly towards the southern ranges of the website. With scroll snap points, we can tell the browser to gracefully stop scrolling in certain points of our document.

There are some cool libraries which implement this with cross-browser compatibility, such as the ever-famous pagePiling.js (which does a lot more things than just scroll snapping), but the native CSS property doesn’t work on Chrome.

CSS scroll snap points work for the horizontal axis as well as for the vertical axis. I’m going to give you an example of a vertical scrolling container with scroll snap points. Hop to Firefox if you’re not there already.

This will only work on Firefox

For a great guide on how to use this, refer to CSS Tricks. The basic syntax you have to use for this is as follows:

.container {
  scroll-snap-type: mandatory;
  scroll-snap-points-y:repeat(px, vh, vw, percentage);
  scroll-snap-destination: x y;
}

Hyphenation

Next up in our CSS features that don’t work on Chrome is hyphenation. Check out this piece of lorem. The upper picture was taken on Chrome, and the lower one was taken on Firefox. They both have hyphenation active, but obviously it only works on Firefox.

Hyphenation in Chrome vs Firefox

The hyphens property is tied to the language attribute you give your HTML, so be sure to use the correct language. Here is the different syntax options you can use in more detail:

.element-that-contains-text {
  hyphens: none;
  hyphens: manual;
  hyphens: auto;
  /* And as usual... */
  hyphens: inherit;
  hyphens: initial;
  hyphens: unset;
}

Normally you’d use auto. But the manual option is quite interesting (although not very practical, I think). On manual you’d be able to suggest a line break. This can be done in two different ways: by typing a hyphen (-), which suggests the line break but prints the hyphen even if there’s not going to be a line break, or by adding a soft hyphen (U+00AD). A soft hyphen won’t print but will break the line if able to.

I have recently been informed by a tweet by Michael Scharnagl of a plan to introduce hyphens to Blink, which is interesting. Let’s hope it comes to Chrome soon.

The element function

This feature is awesome! Its effect is a little bit difficult to pick up on. Here’s my attempt at explaining it. The CSS background property accepts several different values, such as colors and image URLs. In Firefox, you can also use the element() function as a value for the background property. Let’s set up two div elements with some simple markup:

<div id='element-on-the-left'>
  <!-- whatever content here, this will be
  the source for the element() function -->
</div>

<div id='element-on-the-right'>
  <!-- here we will print a background
  with element() and it will be awesome -->
</div>

Next, we will use this markup to generate a live image of the element on the left. This image will be then used as a background for the element on the right, and the markup goes like this:

#element-on-the-right {
  /* set whatever size here and... */
  background: -moz-element(#element-on-the-left);
}

The whole thing will end up looking similar to this (here’s a link to codepen.io which obviously only works on Firefox):

element() CSS function demo

Now, at first I thought this was cool, but not extremely useful. Until I saw this post by Vincent de Oliveira. His ideas using this feature are extensive and really nice! Go check it out.

Sticky positioning

Update: This has been added to Chrome in version 56. Hurray!

No idea how this one went past my sight for the original list. Thanks to reddit user Graftak9000, Geoffrey Crofte and Nathan here in the comments for pointing this one out.

Scroll down. This will work on Firefox and (now) Chrome 56+

This sticks to the specified 'top' value without any JS.

This property value solves the issue that many modern websites using as sticky header have. Nowadays, cross-browser implementations of a sticky header (or sidebar, or whatever) effect include JavaScript in one way or another. Elements with this property will behave as a relative positioned element until it reaches a threshold specified by its top property, at which point it will behave as a fixed position element. I guess the demo up there is self-explanatory. Here’s the syntax for sticky elements:

.element {
  position: sticky;
  top: /* Your value */;
}

Recent versions of Safari also support this but don’t work properly when the parent has overflow: auto; specified. My demo will not work on Safari because it doesn’t include the -webkit- vendor prefix and because it uses said overflow property. Support on Chrome was enabled with a flag on versions 23 through 26 but it was dropped later on. A new implementation is in development, though, so hurray!

Guide to CSS filters

If you’re a web developer, then for one reason or another you’ve probably put your hands (like I have) on image editing software like Photoshop. Also, you’ve probably used the filter menu, which lets you give a layer cool effects such as blur or overlays, and gives you control of contrast, saturation, etc. Well, fear not! Enter CSS filters and say goodbye to the longest minutes of requesting work from our fellow designers: do it yourself! Unlock the powers of the CSS filter property and show the world some magic.

The totally awesome CSS filter property has been around for a while already. Full support was first included in Chrome 18 (March 2012). Firefox adopted it early in version 3.6 but only achieved full support in Firefox 36 (January 2015). A little bit later on, Opera and Safari added support, and nowadays you can use it on most browsers, including the Android native app. Of course, with the exception of cough Internet Explorer (no support) and Microsoft Edge, which includes partial support.

Before actually explaining what any of this does, I’d like to show you a little piece of code I’ve written to let you play around with filters. Go ahead, frolic away:

CSS Filter Playground
Image URL
Opacity
Contrast
Brightness
Saturate
Grayscale
Hue-rotate
Sepia
Invert
Blur
The resulting CSS will appear here.

As you can see, there’s a million things you can do with the CSS filter property. If you haven’t yet, try using a GIF with it. For the lazy ones, here’s a link to a very cool one by Elle Muliarchyk.

CSS filter FAQ


Most of these effects are self-explanatory. But there are some things which may cause a little bit of head scratching. Here’s my attempt at guessing what those are:

Why would I use an opacity filter when I can just use the good old opacity property?

img {
  /* A filter... */
  filter: opacity(50%);
  /* Or normal opacity... */
  opacity: 0.5;
}

These two will yield the exact same visual effect. But most modern browsers use hardware acceleration on filters, which improves the performance of opacity filters relative to that of the regular opacity CSS property.

What is hue-rotate? What the hell does it do to my element?

I’ve based this information on this Wikipedia article. Hue is one of the properties of a color. It is described by the CIECAM02 model as “the degree to which a stimulus can be described as similar to or different from stimuli that are described as red, green, blue, and yellow”. Hue is to a color what timbre is to a sound, basically. Each one of the colors in our HTML element can be located (and represented by a degree) on this scale:

Hue scale

When you use, for example:

filter: hue-rotate(20deg);

…you shift every single one of the colors in your HTML element 20 degrees to the right in the scale up there. CSS uses a little bit of a more rudimentary scale though, so what you get is an approximation.

Hue is a cyclical property. Use my filter generator and apply a 360 degree hue-rotate. You’ll see you get the exact same result with a 0 degree hue-rotate, or with no filter at all.

Which different units should I be using with each filter?

For blur, you use pixels. With blur, every pixel is analyzed and the surrounding pixels up to a distance specified by you with:

filter:blur(20px);

…are blended together to create the blur effect.

For hue-rotate, you use degrees. This has already been explained in the last section. For the rest of the filters you use percentages.

More effects Vol. I: drop-shadow

There are two more functions you can do with the CSS filter property other than the ones I’ve included in my little program up there. One of them is an effect very similar to box-shadow. It’s called drop-shadow and the syntax goes as follows:

img {
  filter: drop-shadow(16px 16px 10px grey);
}

The values stand for h-shadow v-shadow blur spread color, and the result of the example up there is:

CSS drop-shadow example

But what is the difference between drop-shadow and box-shadow?

Here’s a visual example. That’s the drop-shadow filter on the left and the box-shadow property on the right, on the same image. As you can see, the filter respects the alpha layer on your PNG while the box-shadow property applies the effect on the limits of the canvas. If you were to give an element with a drop-shadow filter a pseudo-element such as :after or :before, the filter would respect that, too.

PNG Example with drop-shadow PNG Example with box-shadow

For a more in-detail comparison, I’m going to link you to a great article by the new code: box-shadow property vs. drop-shadow filter: a complete comparison.

More effects Vol. II: SVG filters

The filters directly available with CSS are no more than a bunch of presets built on top of different definitions of SVG filters (which are essentially XML data). Building these specific filters from zero whenever you wanted to add them would be a PITA, so some awesome people at W3C packed up the presumably more popular filters and created the filter property. This does mean though, that you can still add your own home-brewed SVG filters with the following syntax:

img {
  filter: url(#);
}

You can reference on-page anchors by giving your filter an ID and then using that as the URL. If you’d like to go more in-depth on how to create your own filters, check out this article.

Hi there!

Welcome to Brainless Developer. In this blog I will feature memories of my adventures in the world of web development. Expect to see glorious tales of victory as well as stories of how I continuously bang my head against the brick walls of technology. When I try to do anything that’s new to me, I’ll go ahead and try to explain it here. I want to share my learning process with the world and help you make better digital products, and also learn from your criticism.

I am a self-taught web developer from Spain. I studied International Business in Valencia, but halfway through it I discovered it just wasn’t my thing. I have learned extensively from my major though, and I don’t regret having done it. My native language, as you might have imagined, is Spanish. I’ll try my best at blogging in English, you know, one’s got to keep up with the rest of the planet in terms of language skills.

It’s a great day to live.

A bit more than a week before the writing of this post, SpaceX’s Falcon 9 successfully landed on sea on top of an autonomous spaceport drone ship after having deployed its cargo, which was directed towards the International Space Station. I mean, tell me that’s not real life Star Wars. Anyway, things like that are what motivates me to do something that others can enjoy. Contemplating the greatness of those feats makes me feel small and irrelevant to anything, and I want to fight that by helping you make better websites.

Anyway, enough babbling around. I’ll leave you with an awesome (and unbelievably real) picture of a space rocket returning from the skies and gloriously landing on a drone ship, on planet Earth:

Falcon 9 Drone Ship Landing