Odd/Even

I got a request today, how it would be possible to react on odd or even rows in a foreach loop. You often need this to create a striped effect in a table or list for example. So I thought I write a little tutorial about it.

The code

<ul>
  <?php $n = 0; foreach($page->children() as $child): $n++; ?>
  <li class="<?= ($n%2) ? 'odd' : 'even' ?>">
    ...
  </li>
  <?php endforeach ?>
</ul>

If you are too lazy to read on or you know how this works anyway, just copy the code above and play with it :) I'm going to explain now what it does.

How it works

Whenever I need some sort of counter in a foreach loop, I create a new variable right before the loop…

$n = 0;

…and with each row I increase it by one…

$n++;

You can use that counter to display the number before each row for example or you can use it to determine if this is an odd or even row. The easiest way to find out if the number is odd or even is by using the modulus operator, which will return the remainder of a division. In this case, here's what the modulus operator returns for each row:

1%2 = 1
2%2 = 0
3%2 = 1
4%2 = 0

etc…

So we will always get back 1 if it is an odd row number and 0 if it is an even row number. We can use that to add a css selector to our HTML with a little if clause:

<ul>
  <?php $n = 0; foreach($page->children() as $child): $n++; ?>

  <?php if($n%2 == 1): ?>
  <li class="odd">
  <?php else: ?>
  <li class="even">
  <?php endif ?>

  ...
  </li>
  <?php endforeach ?>
</ul>

But in fact this isn't very elegant and we can write that a lot shorter. In PHP 1 is also considered to be true and 0 is considered to be false, so we can reduce…

<?php if($n%2 == 1): ?>
…

… to …

<?php if($n%2): ?>
…

There's also a shorter way to write if clauses:

<?= ($n%2) ? 'odd' : 'even' ?>

If the condition is true, the first string will be echoed, otherwise the second string will be echoed.

Especially when you are using PHP together with HTML instead of a specific template language this is often shorter and easier to read.

All put together, you will get a nice and clean example how to add an odd or even CSS selector to your HTML:

<ul>
  <?php $n = 0; foreach($page->children() as $child): $n++; ?>
  <li class="<?= ($n%2) ? 'odd' : 'even' ?>">
    ...
  </li>
  <?php endforeach ?>
</ul>

CSS3 alternative

The example above is baked into your final HTML and it might not always be the best and most flexible result. A better result could be to use the CSS :nth-child pseudo selector:

li:nth-child(even) {
  background: #ccc;
}
li:nth-child(odd) {
  background: #fff
}

Unfortunately this is not available in all browsers, especially IE prior to IE9 – who would have though that? There are still options to use a javascript plugin to generate the same effect in older browsers or to see it as a progressive enhancement to your design, which won't be visible to users of older browsers.

It's up to you to decide if it is better for your project to go for the server-side solution or the client-side solution. Both are easy to implement and can be extended and adjusted very well.

Update:
I found a way how to write it even shorter. It's a combination of the new ecco() function included in the latest releases of Kirby and a shorter way to write the PHP syntax for counter variables.

<ul>
  <?php $x = 0; foreach($page->children() as $child): ?>
  <li class="<?php ecco($x++%2, 'even', 'odd') ?>">
    <!-- your html for each page -->
  </li>
  <?php endforeach ?>
</ul>

Even shorter…

It can get even shorter if you just add an even class:

<ul>
  <?php $x = 0; foreach($page->children() as $child): ?>
  <li<?php ecco($x++%2, ' class="even"') ?>>
    <!-- your html for each page -->
  </li>
  <?php endforeach ?>
</ul>

And shorter…

If you activate PHP's short tags it can get even shorter…

<ul>
  <? $x = 0; foreach($page->children() as $child): ?>
  <li<? ecco($x++%2, ' class="even"') ?>>
    <!-- your html for each page -->
  </li>
  <? endforeach ?>
</ul>

It's nothing too exciting but one of those things you will need all the time. In my opinion those are the little parts that make our lifes as developers easier or more fun so I wanted to share it with you.