RSS
 

CSS: Rating stars with mouse-over

02 Dec2011

That’s something I thought of quite some time ago, but didn’t have the chance to use anywhere – until now! This will appear in an upcoming project that will probably be released in the next few weeks. I will show you how to make an IMDB-like star rating interface where you rate a product by giving it a number of stars (1 to 5). When you’re not hovering the stars, the control displays the current rating of the product (say, 3.5 stars). When you move the mouse over one of the stars, it is highlighted as well as all other stars to the left of it, so that the number of highlighted stars corresponds to the rating you’re going to give for that product. When you click the star, your rating is processed (which is out of the scope of this article). Except for handling the mouse clicks, everything else is pure CSS – including the mouse-over effects.

Here is what I’m talking about:

 

My goal was to make the control relying solely on CSS for the mouse-over effects, using the :hover pseudoclass to achieve what normally would be done with JavaScript. I decided not to bother with full support of IE6 – although the control is still functional when being clicked, it won’t highlight the stars as you move the mouse over them. That’s due to the well-known fact that :hover works only on A elements in IE6 – bummer…

I also wanted to be able to specify stepless values for the current rating of the product, instead of being restricted to multiples of one star (or half a star, as commonly seen over the web). Achieving this also has the benefit of not having to use more than 3 images – one for each star state. Of course, nothing stops you from rounding the rating percent for aestetic reasons, but it’s nice not to be limited to just 5 values.

If you don’t want to dig through the code to get the idea, here it is:

  • The outermost container is a DIV element with class .stars and is float-ing to the left; the grey star is used as its background and is repeated along the X axis so that 5 of them are displayed.
  • Inside the container there’s a DIV element with class .rating that has its width set in percent that correspond to the current rating we want to display (for 3.5 out of 5 stars, that would be 70%). Its background is the yellow star, repeated along the X axis. Since that DIV is absolutely positioned, it sticks to the left edge of its container – as its width increases, it covers more and more of the grey stars and they become yellow. At 100%, all stars are yellow.
  • The mouse-over effect is achieved with 5 DIV elements nested into each other (see the markup below). Each of them has a fixed height and left padding corresponding to the size of one star image (in this case, 32px). That padding pushes the left edge of each nested DIV 32px to the right, making it smaller. Although you don’t see it, the 5th orange star is actually all 5 of those DIVs stacked on top of each other (and if you look closely, that’s the reason why I’m not using star images with alpha transparency ;) ). The first DIV spans over stars 1-5, the second one is over stars 2-5, and so on – to the last and innermost DIV which only spans over star 5. So, when you move your mouse over the fifth star, this triggers the :hover pseudoclass not only for it, but also for its parent elements (which includes all stars to the left)

HTML markup:

1
2
3
4
5
6
7
8
9
<div class="stars">
<div class="rating" style="width: 70%;"></div>
<div class="star" onclick="event.cancelBubble=true; alert('1 star'); return false;">
<div class="star" onclick="event.cancelBubble=true; alert('2 stars'); return false;">
<div class="star" onclick="event.cancelBubble=true; alert('3 stars'); return false;">
<div class="star" onclick="event.cancelBubble=true; alert('4 stars'); return false;">
<div class="star" onclick="event.cancelBubble=true; alert('5 stars'); return false;">
</div></div></div></div></div>
</div>

CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
.stars { 
  position: relative; 
  float: left; 
  background: url('/images/star_u.png') repeat-x left top; 
  cursor: default; 
}
.stars .star { 
  height: 32px; 
  padding-left: 32px; 
  background: transparent none repeat-x left top; 
  cursor: pointer; 
}
.stars:hover .star { 
  background-image: url('/images/star_u.png'); 
}
.stars:hover .star:hover {
  background-image: url('/images/star_o.png'); 
}
.stars .rating { 
  position: absolute; 
  height: 100%; 
  background: url('/images/star_d.png') repeat-x left top; 
}
.stars:hover .rating { 
  display: none;
}

Notes:

  • You can omit the .rating element if you don’t need it – this will result in all-grey stars when you’re not hovering them.
  • Instead of specifying explicit dimensions for the container (.stars), we make it float:left so that its width automatically matches its content. However, this means that we need to take special measures to ensure that it correctly expands the height of its parent element. To do this, you can either append a dummy DIV with clear:both right after the stars control, or set overflow:hidden on the parent element. An alternative approach is to set the width/height of the control explicitly so that you can remove the float:left setting altogether – whatever suits your environment! If you need the stars only for a read-only indicator for rating, you would just use one .stars element containing the .rating element, without all the .star elements – though in this case you’ll have to explicitly define the .stars element’s dimensions instead of floating it.
  • When handling the onclick event for the .star elements, don’t forget that they are nested – this means that the event will bubble up the DOM tree through all the parent .star elements, unless YOU prevent it by setting event.cancelBubble to TRUE.

Hope this helps somebody. If you have any questions or suggestions on how to further simplify this or make it more elegant, please feel free to use the comments :)

 

Firefly – най-добрият сериал, свалян някога от екран

26 Apr2011

Може да ви звучи твърде претенциозно, но не е далеч от истината. Търсенето в Гугъл за “The best cancelled shows ever” би ви дало безброй такива класации, и Firefly ще присъства в поне 4 от 5 такива списъка. Сериалът излиза през 2002 година и е прекратен след само 11 излъчени епизода (следват още 3 след като решението вече е взето, така че епизодите са общо 14). Тук не говорим за сериали, които просто са изживели живота си и са омръзнали на аудиторията, или са довършили каквато история са имали да разкажат. Някои просто не успяват да получат достатъчно добър шанс за изява и биват прекъснати по причини, нямащи нищо общо с качествата на самия сериал – за огромно мое съжаление, точно такъв е и този случай.

И все пак, за какво става дума? Firefly e фантастичен сериал, но доста по-различен от по-популярните си събратя (Стар Трек, Бойна звезда Галактика, и т.н.). Няма извънземни, нито епични звездни битки с огромни кораби. Най-често Firefly се описва като “космически уестърн”, въпреки че такова определение е точно само в най-общ смисъл. Сценарият залага основно на малки дози от готин хумор, качествен екшън, интересни и много разнообразни персонажи, и завладяващи сюжетни линии.

Историята се развива през 2517г. – човечеството е напуснало Земята и е намерило нова звездна система, която да нарече свой дом. Системата има множество планети и луни, които са били тераформирани и заселени. Централните планети, където са съсредоточени ресурсите и богатствата, се обединяват в Алианс с единно правителство. Независимите външни планети отказват да се присъединят към Алианса, което води до кървава гражданска война. “Кафявите униформи” (browncoats), както са наричани войниците на Независимите светове, губят войната с Алианса и в крайна сметка всички планети стават част от единното правителство.

Действието в сериала започва шест години след края на войната, и описва премеждията на девет души, събрани по повеля на съдбата на космическия кораб “Серенити” (от англ. – спокойствие), под командването на капитан Малкълм Рейнълдс – печен ветеран от Обединителната война, в която се е бил на страната на Независимите. Всеки от пасажерите има собствена причина да бъде на кораба – едни бягат от дългата ръка на Алианса, други търсят приключения, трети – пари, а пък за някои – благодарение на краткия живот на сериала, изобщо не разбираме какво ги води. Въпреки че са с много различни истории обаче, те заедно се превръщат в сплотено семейство, за което всеки от тях би жертвал дори живота си.

Основната причина за неуспеха на сериала вероятно е начинът, по който той бива представен на зрителите. FOX (телевизионната компания) решава в последния момент да промени реда на излъчване на епизодите, като избира водещ да бъде вторият епизод вместо предвидения първи – в резултат на това повечето хора остават доста объркани и без никаква идея как е започнала историята. Предвиденият първи епизод всъщност е излъчен последен, което допълнително скрива от зрителите ценна информация за сюжета. Резултатът от тази глупост е, че първата излъчена версия представлява просто миш-маш от несвързани помежду си епизоди, неследващи никаква хронология. В крайна сметка рейтингът на шоуто е толкова нисък, че FOX му отрязва въжето и прекратява проекта.

Въпреки фиаското на FOX, сериалът успява да привлече известно количество ревностни последователи, наричащи себе си “browncoats”. След края на сериала, с помощта на рекламни кампании и организирано изкупуване на DVD-версията на Firefly (някои хора купуват десетки boxset-ове, за да ги подаряват на свои познати), феновете успяват да подкрепят финансово продуцентите и да подпомогнат заснемането на пълнометражния филм “Serenity” (излязъл 2005г.), който успява някакси да закърпи сюжетните дупки, останали след ранния край на сериала, и да даде на феновете така жадуваната развръзка на историята. По този начин Firefly става прецедент – шоу, свалено от екран, успява успешно да изкара свое филмово продължение!

Тази статия е моят принос за популяризирането на Firefly – повече от 8 години след излизането на последния епизод, споменът за този сериал все още е жив и набира нови фенове. Ако все още не сте попадали на него, можете да го намерите в един от най-големите тракери в България. Съветвам ви да отделите два часа поне за пилотния епизод, и после не забравяйте да споделите мнението си в коментарите под статията! :)

 

Nico vs. Michael

13 Apr2011

 

PHP: Using functions/expressions in HEREDOC strings

29 Mar2011

If you have any experience with PHP at all, you’ve probably used HEREDOC strings. The syntax is quite useful for long strings that span on multiple lines, but I always disliked the fact that if you wanted to use the result of a function, you need to store it in a variable as an intermediate step:

1
2
3
4
$time = date('r'); // example value: Tue, 29 Mar 2011 17:04:28 +0300
$string = <<<HEREDOC
Now is {$time}
HEREDOC;

Unfortunately, PHP doesn’t provide any direct means for calling functions or outputting expression results in HEREDOC strings. The problem here is that, unless the thing in the curly braces starts with a dollar sign, it can’t be recognized by PHP as something to be replaced – you can’t just put {date(‘r’)}. Functions doesn’t start with a dollar sign, so you can’t use them. Object methods work fine though, because the object variable does start with a “$”.

We can use this behavior in order to devise a very neat workaround to our problem: if PHP wants a $ in the beginning, why don’t we just store the function name in a variable? That’s one of the less popular features of PHP – and for good reasons – but in this particular case it could be very useful. So, we can change our example above to this, and it will work:

1
2
3
4
$date_func = 'date'; // the name of the function as a string
$string = <<<HEREDOC
Now is {$date_func('r')}
HEREDOC;

Now, let’s step this up a bit, shall we? Take a look at this example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function heredoc($param) {
    // just return whatever has been passed to us
    return $param;
}
 
$heredoc = 'heredoc';
 
$string = <<<HEREDOC
\$heredoc is now a generic function that can be used in all sorts of ways:
Output the result of a function: {$heredoc(date('r'))}
Output the value of a constant: {$heredoc(__FILE__)}
Static methods work just as well: {$heredoc(MyClass::getSomething())}
2 + 2 equals {$heredoc(2+2)}
HEREDOC;
 
// The same works not only with HEREDOC strings,
// but with double-quoted strings as well:
$string = "{$heredoc(2+2)}";

Told you it was neat, isn’t it? :) The “heredoc” function is just a wrapper – it accepts a single argument which is returned unmodified, and the name of this function is stored in a global variable that can be used anywhere in your application. The name of the function and the name of the global variable are completely customizable, so the “heredoc” name is just a suggestion. $heredoc() will be called as a function, and the expression in the parentheses will be evaluated as any other PHP code. The result of that expression will be given to the heredoc function which, in its turn, just returns it and puts it in the HEREDOC string.

 
1 Comment

Posted in 1010011010

 

Домашен файлов сървър – #4 – Софтуер

11 Feb2011

Надявам се да съм ви помогнал с предните 3 статии по темата – днес обаче стигаме до последната критична част от плана! След като сме се погрижили за цялата хардуерна страна на задачата, остана само да влеем живот в системата, като инсталираме целия нужен софтуер за файловия сървър.

Тази последна статия ще бъде малко по-различна от предните. Досега ви давах съвети, къде конкретни, къде не чак толкова, за това кои пътища да следвате, за да постигнете целта. И докато това върши работа при избора на хардуер, нещата със софтуера седят маааалко другояче. Има няколко коренно противоположни основни варианта, които можете да изберете, а пък след това под-вариантите стават дори десетки.

Преди да се запознаем с тези варианти обаче, няколко странични въпроса…

Read the rest of this entry »