Jelenlét-érzékelés infravörös fény segítségével

Végre hosszú idő után előkerült a PICkit a fiókból. Az [intlink id=”559″ type=”post”]el%u0151z%u0151 PIC[/intlink]-es próbálkozásom után most egy kicsit bonyolultabb probléma megoldására vállalkoztam. Konkrétan arra, hogy a kütyü képes legyen érzékelni valakinek a jelenlétét. Erre a leggyakrabban alkalmazott módszer infravörös fényt vetít a vizsgált térrész felé, és méri a visszaverődött fény mennyiségét. Minél több fény verődik vissza, annál közelebb van a tárgy, amiről visszaverődött. Az elmélet egyszerű, és mint azt a továbbiakban olvashatjátok, a gyakorlat se sokkal bonyolultabb.

Az első probléma ami felmerült, az a jelentős háttérzaj kérdése. Az infravörös tartományban a nap és a legtöbb mesterséges fényforrás is sugároz, ráadásul sokkal erősebben, mint egy ilyen alkalmazásban szóba jöhető infra-led. A háttérzaj és az infra-led jelét szétválasztani csak úgy lehet, ha modulált jelet sugározunk a térbe, és ezt a modulált jelet keressük a mért értékekben is. Léteznek olyan infra-vevők, melyek hardveresen támogatják a modulált jel érzékelését (pl. TSOP), de hasonló alkatrészt tucatnyi boltot körbejárva sem találtam (ha tud valaki olyan boltot, ahol vásárolható ilyen, kérem írjon). Ilyen célezköz hiányában a modulációt szoftveresen oldottam meg.

A szoftveres moduláció miatt a hardver rendkívül egyszerű lett, a következő alkatrészekre volt szükségem:

  • Pic16F690
  • 1db infra led
  • 1db fotodióda
  • 1db npn tranzisztor
  • 4db 1kOhm ellenállás
  • 2db vörös led (egy a bekapcsolt állapotot jelzi – folyton világít, egy pedig a végeredményt adja meg, hogy érzékel-e jelenlétet az eszköz)

A munkát minimalizálandó felhasználtam a programozóhoz adott próbapanelt, amin beépített ledek állnak rendelkezésre, ezeket felhasználtam az állapotjelzések számára, így csak a fotódiódát és az infraledet kell hozzákötni, ami egy breadboard segítségével könnyedén kivitelezhető. Az infra-ledet a PIC rc0 kimenete fogja meghajtani, egy ellenállással bekötve ez a rész készen van. A kimenetet jelző led az rc1, a power-led az rc2-re van kötve hasonló módon. A fotódiódát a tranzisztorral erősítve kötjük a beépített A/D konverter bemenetére, hogy erősebb jelet kapjunk, ezzel megnövelve az érzékelés felbontását. A további félreértések rövidre zárásához felraktam egy kapcsolási rajzot:

pdetector.png

A szoftver ezzel a következő módon tud együttműködni: az alapötlet az, hogy kikapcsolt infra-leddel lemérjük a bejövő fény mennyiségét, majd bekapcsoljuk az infrát, és újra mérünk. A bekapcsolt illetve kikapcsolt infra-led melletti mérések különbsége adja meg az infra-led által leadott és visszavert fény mennyiségét. Ha ez a különbség több iteráció után is meghaladja a küszöbértéket, akkor a kimeneten jelezzük az érzékelt jelenlétet. Azaz két paraméter a küszöbérték (mekkora különbséget várunk el kikapcsolt és bekapcsolt infra-led melletti mérések között), és a kitartás (hány iteráción át kell tartani ezt a különbséget).

És íme, a kód. A dolog nehézségét jelzi, hogy a legtöbb időt két érték összehasonlítása vette el. A kódban szereplő makrót a Microchip MPasm leírásából vettem, én egy kétszer olyan hosszú megoldást csináltam elötte.


#include __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF &
_IESO_OFF & _FCMEN_OFF)

;presence detector code.
;assumed peripheres:
; infra-led on RC0
; photo-diode connected to AN0
; detected proximity output on RC1
; power led on RC2
;
;we measure input on photo diode, while infra-led is turned off.
;then we measure again with turned on infra-led.
;if the infra-ray is reflected from anything, the second measurement
;should return a higher value

;=================================================
;========VARIABLES================================
;=================================================

cblock 0x20
offmeasure ;stores measurement without infra led
onmeasure ;stores measurement with infra led
output ;output bits
waitcount ;wait count
surecount ;make sure that something is there and not moves
endc

OUT_ILED EQU H’0000′ ;bit for infra led
OUT_RES EQU H’0001′ ;bit for output
OUT_POWER EQU H’0002′ ;power led

THRESHOLD EQU H’0002′ ;threshold for measurment gain

SURENESS EQU H’000C’ ;number of measurements before we’re sure in the result

;===================================================
;==============macros for selecting banks
;====================================================
SELECT_BANK0 macro
bcf STATUS,RP0
bcf STATUS,RP1
endm

SELECT_BANK1 macro
bsf STATUS,RP0
bcf STATUS,RP1
endm

SELECT_BANK2 macro
bcf STATUS,RP0
bsf STATUS,RP1
endm

SELECT_BANK3 macro
bsf STATUS,RP0
bsf STATUS,RP1
endm

;==============================================
;=====MACRO TO WAIT=============================
;==============================================

WAIT macro us
local a = 0
while a < us
nop
a += 1
endw
endm

;============================================
;========EXECUTE A MEASUREMENT===============
;============================================

MEASURE macro
WAIT 5
bsf ADCON0,GO ; start conversion
btfsc ADCON0,GO ; this bit will change to zero when the conversion is complete
goto $-1

movf ADRESH,w

btfsc output,OUT_ILED
goto $+3
movwf onmeasure
goto $+2
movwf offmeasure
nop
endm

;========================================
;=======SWITCH output led================
;========================================

SWITCH_ILED macro
movlw 0x01
xorwf output,F
endm

;========================================
;========REFRESH OUTPUT==================
;========================================

REFRESH_OUTPUT macro
movfw output
movwf PORTC
endm

;======================================================
; compare file to constant and jump if file
; >= constant.
;======================================================
cfl_jge macro file, con, jump_to
movlw con & 0xff
subwf file, w
btfsc STATUS, C
goto jump_to
endm

;===============================================
;==============MAIN PROGRAM=====================
;===============================================
org 0
Init:
;set variables to zero
movlw 0x00
movwf output
movwf onmeasure
movwf offmeasure

;set powerled on
bsf output,OUT_POWER

;initialize devices
SELECT_BANK1
movlw 0xFF
movwf TRISA ; Make PortA all input
clrf TRISC ; Make PortC all output
movlw 0x10 ; A2D Clock Fosc/8
movwf ADCON1
SELECT_BANK2
movlw 0xFF ; we want all Port A pins Analoge
movwf ANSEL
SELECT_BANK0
movlw 0x01
movwf ADCON0 ; configure A2D for Channel 0 (RA0), Left justified, and turn on the A2D module

Loop:
MEASURE ;measure with light off
SWITCH_ILED ;turn light on
REFRESH_OUTPUT
call SubWait ;wait a bit

MEASURE ;measure with light on
SWITCH_ILED ;turn light off
call DecideOutput ;decide output
REFRESH_OUTPUT
call SubWait ;wait a bit
goto Loop

;==============================================
;=====Decide output============================
;==============================================
DecideOutput:
;onmeasure-offmeasure >= threshold
movfw offmeasure
subwf onmeasure,F
cfl_jge onmeasure,THRESHOLD,DecideYes
goto DecideNo
DecideYes:
;bsf output,OUT_RES
incf surecount,F
goto DecideOutputReturn
DecideNo:
clrf surecount
bcf output,OUT_RES
DecideOutputReturn:
cfl_jge surecount,SURENESS, SwitchOn
goto SwitchOff
SwitchOn:
bsf output, OUT_RES
return
SwitchOff:
bcf output, OUT_RES
return

;===========================================
;===========Subroutine for long wait========
;===========================================
SubWait:
movlw 0xFF
movwf waitcount
StartWait:
WAIT 100
decfsz waitcount,F
goto StartWait
return

;===============================================
;=====PROGRAM END===============================
;===============================================
end

A kütyüt felprogramoztam, a perifériákat megépítettem, és pár iteratív hibajavítás/paraméterfinomítás után eljutottam arra az állapotra, amit elégségesnek neveztem a koncepció működésének a bizonyítására.

dscf1957_small.jpeg

A fenti köntörfalas megfogalmazás nem költői önkifejezés, és nem is véletlen. Az eszköz működik, de épp hogy. A környezet által kifejtett fényerő fehérzajként adódik a rendszerhez, és csak magas “kitartás” és “küszöbérték” paraméter mellett lehet kiszűrni a téves jelzéseket. Ennek az az eredménye, hogy kb. két másodperc után jelzi ha 5cm-nél közelebb teszem a kezemet az infra-led+fotódióda pároshoz. 10cm-nél már bizonytalan a mérés, és akkor is előfordul egy-egy téves jelzés, ha nincs semmi a közelben.

Ezen problémák orvoslására több ötletem is van, egy részük azonnal megoldódna, ha találnék egy rendes infra adó-vevőt. Persze ötleteket, javaslatokat, hasonló problémákban szerzett tapasztalatokat szívesen fogadok.

Hibrid CSS menü

Translated with the permission of A List Apart Magazine and the author[s]. (Az A List Apart oldal és a szerző engedélyével lefordítva.)

Az eredeti cikk 2005. március 30. óta elérhető itt.

Tudom, mire gondoltok… „Biztosan szükség van még egy cikkre a CSS legördülõ menükrõl?” Hadd gyõzzelek meg titeket. Mi történne, ha lenne egy tiszta, jól struktúrált menünk, ami egyszerre hordozná magában a legördülõ menük dinamizmusát, egyszerû kódját de megszüntetné a fõ problémáit (nem is beszélve a szép megjelenésrõl)?

Translated with the permission of A List Apart Magazine and the author[s]. (Az A List Apart oldal és a szerző engedélyével lefordítva.)

Az eredeti cikk 2005. március 30. óta elérhető itt.

Tudom, mire gondoltok… „Biztosan szükség van még egy cikkre a CSS legördülõ menükrõl?” Hadd gyõzzelek meg titeket. Mi történne, ha lenne egy tiszta, jól struktúrált menünk, ami egyszerre hordozná magában a legördülõ menük dinamizmusát, egyszerû kódját de megszüntetné a fõ problémáit (nem is beszélve a szép megjelenésrõl)?

A gondok a legördülõ menüvel:

  1. az almenük pontjai nem érhetõek el addig, amíg nem kezdjük el az egész menürendszert használni, és
  2. nem ad megfelelõ tájékozódási pontot a felhasználónak. Nehézkes lehet vele az oldalon belüli navigáció, mert mindig le kell gördíteni a menüt az oldalak váltásához.

Ez a technika egy bombabiztos megoldás a böngészõkkel való kompatibilitás és a hozzáférhetõség biztosítására még azon felhasználók számára is, akik régi böngészõt használnak, esetleg problémáik vannak a legördülõ menük használatával, akár mert nem tudja, akár mert nem találja kedvezõnek a legördülõ menük alkalmazásának elveit. Emellett sokkal pontosabb információt ad a hagyományos legördülõ menüknél az oldalon belüli pozícióról.

Figyelem! Ez a technika nem mûködik nagy elemszámú listákra, ahol a hagyományos legördülõ menük még jól használhatóak vagy összeomlanak a puszta tömegük alatt, a nézõponttól függõen.

Egy olyan hibrid menüt fogunk készíteni, ami vízszintesen halad keresztül az ablakon. Két szintû navigációt használ (példánkban a fõ témák és a kapcsolódó oldalak). A menünkben legördülõ hozzáférést biztosítunk minden oldalnak mindkét navigációs szinten, valamint állandóan megjelenítjük a kiválasztott témához tartozó választási lehetõségeket, emlékeztetve a felhasználót, hogy az oldal melyik részén van. Emellett a kódja egyszerû és gyorsan mûködõ lesz.

Jól hangzik? Vágjunk bele.

Elõször is vegyünk egy listát

Készítsünk egy listát az építészeti korszakokról és az õ nagyobb alakjaikról. Egy ID-t kapcsolunk az <ul> elemhez és „off” illetve „on” class-t a menülista elemeihez (ami persze feltehetõleg nem a legjobb megoldás, de a cikk céljainak megfelel):

Formázzuk meg!

Ez egy jó hely az induláshoz. Egy egyszerû, szemantikus jelölés, ami könnyen karbantartható és egy helyen található. Úgy néz ki ahogy az elvárható.

Az elsõ dolog, amit a CSS felhasználásával el fogunk érni, az az, hogy az elsõ szintjét vízszintesen jelenítjük meg (a float tulajdonság felhasználásával) és elrejtjük az alsóbb szinteket. A linkeket pedig félkövéren, színezve és kerettel jelenítjük meg.


#nav li {
/*float the main list items*/
margin: 0;
float: left;
display: block;
padding-right: 15px;
}

#nav li.off ul, #nav li.on ul {
/*hide the subnavs*/
display: none;
}

#nav li a {
/*for all links in the list*/
color: #f90;
font-weight: bold;
display: block;
height: 15px;
width: 100px;
border: 1px solid #29497b;
padding: 5px;
}

Most helyezzük el a második listaszintet a fõ lista alá, hogy amikor újra megjelenik, amegfelelõ helyen legyen.


#nav li.off ul, #nav li.on ul {
/*put the subnavs below and hide them all*/
display: none;
position: absolute;
top: 33px;
height: 15px;
left: 0;
padding-top: 10px;
}

Végül jelenítsük meg az almenüt az aktív tématerülethez, ami a példánkban „Modern”. A legjobb megoldás erre, ha egyetlen központi, mindent lefedõ menüt használunk, egy osztály használata, mondjuk, a „Modern” elemen, és ennek megfelelõ kijelölõket használunk. Ebben a cikkben, ami egy másik oldalon belül lesz közzétéve, és önmagában is elégségesnek kell lennie, egy „on” osztályt adunk a kiválasztott témához és „off”-ot az inaktív témákhoz.


#nav li.on a {
/*change border color for active topic area*/
border: 1px solid #f90;
}

#nav li.on ul a, #nav li.off ul a {
/* cancel inherit of border
on subnav of active topic */
border: 0;
}

#nav li.on ul {
/*display active subnav list*/
display: block;
}

Még hozzáadunk néhány keretet, és így kapjuk az itt látható eredményt.

És akkor mindenki gördült, de egy kiesett…

Most pedig aktiváltjuk a legördülõt. Ez nem különbözik lényegesen a többi CSS legördülõ menütõl – a hover a li elemen jelenik meg, így az IE alatt nem fog mûködni a rosszul implementált :hover pszeudo-osztály miatt. Ezzel is mindjárt foglalkozunk. A következõ CSS eltünteti a kereteket a második listaszinten, a kiválasztott almenüt mindig megjeleníti, és beállítja az inaktív menük megjelenítését, ha az õsükre rámutatunk az egérrel. Beállítjuk a z-index tulajdonságot is annak érdekében, hogy az egérrel kiválasztott téma mindig elsõbbséget élvezzen az aktuális téma almenüjével szemben.


#nav li.on ul a, #nav li.off ul a {
float: left;
/*ie doesn't inherit the float*/
border: 0;
color: #f90;
width: auto;
margin-right: 15px;
}

#nav li.on ul {
/*display the current topic*/
display: block;
}

#nav li.off:hover ul {
/* display the other topics when
their parent is hovered */
display: block;
z-index: 6000;
}

We’ll make it a little more user-friendly, with a background on the hovered tabs.
Egy kicsit felhasználóbarátabbá is tesszük azzal, hogy hátteret váltunk a kijelölt(:hover) füleken.


#nav li.off a:hover, #nav li.off:hover a {
background: #29497b;
color: #f90;
}

Itt lehet megtekinteni, hol is tartunk.

Foglalkozzunk a „különleges” böngészõinkkel…

Két választás van azon böngészõk felé, mint az Internet Explorer, amik nem támogatják a :hover osztályt a <a> elemen kívül. Hagyhatjuk úgy, ahogy van, tudva, hogy mûködni fog néhány éven belül, amikor minden böngészõ támogatni fogja a :hover osztályt (lekopogom). Ugyanakkor nyugodtak lehetünk abban a tudatban, hogy minden navigációs elem látható és elérhetõ minden felhasználó számára. Esetleg megpróbálhatunk egy kis JavaScript kódot írni, ami megfelelõen átírja a CSS kijelölõket úgy, hogy az IE is megérti, ezáltal elérhetõvé téve a legördülõ menü dinamizmusát mindenki számára.

(A mûködés IE-ben úgy-ahogy értelmezhetõ) Kicsit igazítani kell az elhelyezésen a csillag-hack segítségével:


#nav li.off ul, #nav li.on ul {
/*put the subnav below*/
top: 33px;
*top: 44px; /*reposition for IE*/
}

Tehát a menü nagyszerûen mûködik a modern, szabványkövetõ böngészõkben, és korlátozottan, funkcionálisan mûködik megfelelõ elhelyezéssel az Internet Explorer 5 és 6 böngészõkben is. Egy kis segítséggel a legördülõ menüt az Internet Explorer 5-ös és 6-os verzióiban is mûködésre lehet bírni. Ehhez egy egyszerû JavaScipt kódot kell írni a kijelöléskor a kijelölõk módosítására, ez az IE 5.x és 6.x verziókon mûködik (Windows alatt). Köszönet a módszerért Patrick Griffiths-nek és Dan Webbnek, akik a „Suckerfish Legördülõ menükkel”elindítottak a CSS-alapú menürendszerek fejlesztése felé (az írás magyarul az oldalon olvasható [[Suckerfish menük]] címmel). Az õ JavaScript részletük a következõképpen néz ki:


startList = function() {
if (document.all && document.getElementById) {
navRoot = document.getElementById("nav");
for (i=0; i<navRoot.childNodes.length; i++) {
node = navRoot.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
}
node.onmouseout=function() {
this.className=this.className.replace
(" over", "");
}
}
}
}
}
window.onload=startList;

Még egy egyszerû módosítás szükséges a CSS-en:


#nav li.off:hover ul, #nav li.over ul {
display: block;
z-index: 6000;
}

#nav li.off a:hover,
#nav li:hover a,
#nav li.over a {
background: #29497b;
color: #f90;
}

ahhoz, hogy az „.over” osztály hozzáadása a lista elemekhez, amelyeket kijelölünk, mûködésre bírja a rendszert az IE/Win felhasználók számára. Nem mintha nem lenne érdemes egy új böngészõben gondolkodni, de egyelõre folytatjuk a tömegek kiszolgálását olyan módon, amit már õk is megszoktak.

Tehát ez lenne az. Egy inkrementális változtatás, talán, a korábbi CSS legördülõkhöz képest, de egy másik szemszög ahhoz, hogy felfedezzük azokat az eseteket, ahol tényleg hasznos a navigáció megjelenítése ahelyett, hogy elrejtenénk egy legördülõ menü belsejében.

És lehet szép isl?

Ok, hogy nem túl szép még. Nem tehetem meg, hogy egy sokkal szebb grafikával ellátott verziót mutatok ezzel a technikával a pedánsak kedvéért a való világnak. Néhány változtatással, a CSS sprite navigációs képekkel (köszönet Dave Sheanak, egy fénykép New York Citybõl, egy kicsit több CSS, és olyan menürendszert kapunk, ami megmutatja a CSS igazi erejét, ha grafikai tervezéssel kombináljuk. Kipróbálható a végleges Hibrid CSS legördülõ menü, tökéletesen mûködõképes az összes modern böngészõven.

A szerzőről

Eric Shepherd az alapítója az arkitrave web media-nak, egy kis, webbel és grafikával foglalkozó cégnek a new yorki Buffaloban. Éppen egy építészeti diplomát szerez (Master of Architecture degree) a a Buffaloi Egyetemen. Emelett még zongorista is. A munkája megjelent a CSS Zen Garden oldalon, és stratégiai partnere a Nepo Strategies-nek, egy buffaloi e-kereskedelmi és webes stratégiai cégnek. Már foglalkozik vele, hogy hogyan magyarázza el az XHTML, a CSS és Javascript DOMmal kombinált erejét a zseniális egyhónapos lányának, Naia-nak.

Translated with the permission of A List Apart Magazine and the author[s]. (Az A List Apart oldal és a szerző engedélyével lefordítva.)

Az eredeti cikk 2005. március 30. óta elérhető itt.

Suckerfish menük

Translated with the permission of A List Apart Magazine and the author[s]. (Az A List Apart oldal és a szerző engedélyével lefordítva.)

Az eredeti cikk 2003. november 7. óta elérhető itt.

A „DHTML” legördülő menük maguk után vonták az otromba, böngészőspecifikus hackelésekkel teletömött Javascript kódokat, amik az egyébként elegáns, szemantikus HTML kódot meglehetősen hozzáférhetetlenné A hozzáférhető/hozzáférhetetlen fogalmakon a webtervezői szókincsben megfelelő accessibility kifejezést értem. teszik. Ó, azok a pehelykönnyű, hozzáférhető, szabványos, böngészőfüggetlen módszerek! Tekintsd meg a Suckerfish Suckerfish: Brehm és Wikipedia alapján rövidszárnyú bojtorjánhal. Ez a hal a Gályatartóhal-félék családjába tartozik. Ezek a halak már az ókorban is ismertek voltak a Földközi-tenger vidékén, a halak különlegessége, hogy más halakhoz, esetenként hajókhoz kapcsolódtak, velük vitették magukat. Konkrétan a bojtorjánhalról Brehm ezt írja: „Elterjedésének határa valószínűen egybeesik a kardoshalakéval, mivel többedmagával ezekre tapadva viteti magát. (Brehm: Az állatok világa) menüket!

Translated with the permission of A List Apart Magazine and the author[s]. (Az A List Apart oldal és a szerző engedélyével lefordítva.)

Az eredeti cikk 2003. november 7. óta elérhető itt.

A „DHTML” legördülő menük maguk után vonták az otromba, böngészőspecifikus hackelésekkel teletömött Javascript kódokat, amik az egyébként elegáns, szemantikus HTML kódot meglehetősen hozzáférhetetlenné A hozzáférhető/hozzáférhetetlen fogalmakon a webtervezői szókincsben megfelelő accessibility kifejezést értem. teszik. Ó, azok a pehelykönnyű, hozzáférhető, szabványos, böngészőfüggetlen módszerek! Tekintsd meg a Suckerfish Suckerfish: Brehm és Wikipedia alapján rövidszárnyú bojtorjánhal. Ez a hal a Gályatartóhal-félék családjába tartozik. Ezek a halak már az ókorban is ismertek voltak a Földközi-tenger vidékén, a halak különlegessége, hogy más halakhoz, esetenként hajókhoz kapcsolódtak, velük vitették magukat. Konkrétan a bojtorjánhalról Brehm ezt írja: „Elterjedésének határa valószínűen egybeesik a kardoshalakéval, mivel többedmagával ezekre tapadva viteti magát. (Brehm: Az állatok világa) menüket!

Először a HTML

Először is, válasszuk a legjobb módszert a menü leírásához — egy listát. Példánkban egy egyszerű HTML sorszámozás nélküli listát használunk.

<ul>
  <li>Sunfishes

    <ul>
      <li><a href="">Blackbanded sunfish</a></li>
      <li><a href="">Shadow bass</a></li>
      <li><a href="">Ozark bass</a></li>
      <li><a href="">White crappie</a></li>
    </ul>

  </li>

  <li>Grunts

    <ul>
      <li><a href="">Smallmouth grunt</a></li>
      <li><a href="">Burrito</a></li>
      <li><a href="">Pigfish</a></li>
    </ul>

  </li>

  <li>Remoras

    <ul>
      <li><a href="">Whalesucker</a></li>
      <li><a href="">Marlinsucker</a></li>
      <li><a href="">Ceylonese remora</a></li>
      <li><a href="">Spearfish remora</a></li>
      <li><a href="">Slender suckerfish</a></li>
    </ul>

  </li>
</ul>

Tényleg eléggé magától értetődő — tiszta és elegáns HTML, ami a hozzáférhetőséget biztosítja. De ezt most átalakítjuk egy dinamikus listává — a listaelemek első szintje egy vízszintes menüsávot fog alkotni, ebből fognak legördülni a második szintű listák.

Formázzuk meg!

Kezdésként minden listaelemet piszkáljunk meg egy kicsit — nevezetesen a margót és kitöltést nullára állítjuk, a listaelemek jelzését pedig kikapcsoljuk:

ul {
  padding: 0;
  margin: 0;
  list-style: none;
  }

A következő lépésben a lista első szintjét átalakítjuk egy vízszintes menüsávvá. Többféle technika van erre, amiket máshol részletesebben kifejtenek. Megjelölhetnénk az elemeket a display: inline; jellemzővel, de ebben a példában inkább balra lebegtetjük őket.

li {
  float: left;
  position: relative;
  width: 10em;
  }

Az elemek helye position: relative;-ra lett állítva, mivel a beágyazott listákat az első szinthez képest relatívan helyezzük majd el, a fix (!) szélességmegadás meg azért szükséges, hogy elérjünk bizonyos méreteket. A legördülő menü lassan összeáll.

Ezek után nézzük a lista második szintjét, ami a tényleges legördülő menü lesz:

li ul {
  display: none;
  position: absolute;
  top: 1em;
  left: 0;
  }

Ez a listák második szintjét abszolút módon helyezi el (kiemeli a HTML folyamból, és külön kezeli őket), és alapértelmezetten meg nem jelenítettekké állítja. Abban az esetben, ha a display: none; részt display: block;-ra cserélnénk, akkor látjuk szükségét a top és a left értékek beállításának az Internet Explorerben, mert ezek nélkül az IE a második szintű listákat az ősük jobb felső sarkába helyezi a bal alsó helyett. Sajnos ez az IE megoldás elkavarja a dolgokat az Opera-hoz hasonló böngészőkben, így ezekben a következő CSS kódra van szükség a top és left paraméterek beállításához:

li > ul {
  top: auto;
  left: auto;
  }
Angolul: And now, making the sucker work. Lefordíthatatlan szójáték, az angol suckerfish névvel játszik.

És most rakjuk hozzá az összekapcsolást! Ahhoz, hogy a második listaszintet megjelenítsük, amikor az első szinten a pontok „kiválasztódnak”, egyszerűen a következő kódot kell hozzáadni:

li:hover ul { display: block; }

Ami annyit jelent, hogy bármely elem, ami egy olyan pont alatti listában szerepel, amire az egérkurzor rámutat, megjelenítendő.

Végül, mert a listaelemek balra vannak lebegtetve, a tartalmat alattuk függetleníteni kell a lebegtetéstől a clear: left formázás kijelölésével.

Várjunk egy pillanatot!

”Ez a legördülő halandzsa nem működik!” – hallom az olvasók 102,6 százalékát (vagy a legfrissebb, éppen csökkenő hányadukat) kiabálni. Igen, mint kitalálható, az Internet Explorer felhasználóiról beszélek. Minél többet használod egyszerű szörfözőként, vagy webfejlesztőként a Mozillához hasonló böngészőket, annál feltűnőbb, hogy mennyire nevetséges az Internet Explorer, ha a webes szabványokról esik szó. A :hover pszeudoosztálynak elvben minden elemre működnie kellene, de az Internet Explorerben csak a linkekre működik. Pont. Mi a haszna a legördülő menünek, ha csak a böngészők -2,6 százalékán működik? Hogy őszinték legyünk, nem sok. Egy kicsit többet kell még varázsolnunk.

A mentőöv: DOM-szkriptelés

Ugyan megállapítottuk, hogy az IE ugyan nem támogatja a :hover pszeudo-osztályt, de a Document Object Model használatával egyszerűen kapcsolhatunk egéreseményeket (mouseover, mouseout) bármilyen elemhez. Ez jó hír számunkra, mert azt jelenti, hogy egy rövid JavaScript kódocskával hatékonyan orvosolhatjuk az IE :hover gondjait.

Mivel az IE vak, ahhoz, hogy azonosítsuk a :hover pszeudoosztály tulajdonságait, más módszert kell találni. A JavaScript segítségével manipulálhatuk a className tulajdonságát egy elemnek, így először egy kicsit a CSS-t kell megváltoztatnunk:

li:hover ul{ display: block; }

helyett a következő kód használható:

li:hover ul, li.over ul{ display: block; }

Ezután meghívhatjuk a :hover CSS szabályokat a kívánt elemre, ha hozzáadjuk az over osztályt a kívánt elemhez. Szükségünk lehet továbbá arra, hogy megmondjuk az IE-nek, hogy mely UL elemek szolgálnak az oldalon legördülő menüként. Ez egy id hozzáadásával tesszük meg a listánk gyökér ul elemére:

Ezáltal a

<ul>

kódból a következő lesz:

<ul id="nav">

Most, hogy tudjuk azonosítani a gyökér ul elemét a legördülő listánknak, kiemelhetjük ezt az elemet, és végigmehetünk az összes gyerekelemén, hozzáadva a mouseover és mouseout eseményeket az összes li elemhez a belsejében. Ezt így tehetjük meg:

startList = function() {
if (document.all&&document.getElementById) {
navRoot = document.getElementById("nav");
for (i=0; i<navRoot.childNodes.length; i++) {
node = navRoot.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
  }
  node.onmouseout=function() {
  this.className=this.className.replace(" over", "");
   }
   }
  }
 }
}
window.onload=startList;

A lap betöltésekor a startList függvény meghívódik. Ez meghatározza, hogy a böngésző IE 5 vagy újabb a document.all objektum és a document.getElementById függvény létezésének vizsgálatával. Ez egy picit nyers megoldás, de rövid és egyszerű, és mivel mi egy kompakt megoldást szeretnénk, ez is megteszi. Ezután végiglépked a listákon, engedélyezve a mouseover és a mouseout eseményeket, amik hozzáadják/eltávolítják a over osztályt a className tulajdonságához az elemnek.

Így már működik. Probléma esetén érdemes megnézni a megjegyzésekkel ellátott példa vázat működés közben.

Kopoltyúk, uszonyok, pikkelyek…

Eddig amit csináltunk, egy kicsit meztelennek tűnik. Ez a cikk csak az ötlet alapjait mutatja be, de CSS segítségével sokkal szebben meg lehet valósítani. Egy nyilvánvaló kiindulópont lehet háttérszín hozzárendelése a második listaszinthez.

Miután visszaállítottuk a top és left tulajdonságokat, ahogy korábban leírtuk, a legördölő menük a szép példában közvetlenül a feliratok alatt jelennek meg a legtöbb modern böngészőben, de sajnos nem mindben. A Safari 1.0-ban még mindig a képernyő bal felső sarkából gördülnek le.

További használhatósági és hozzáférhetőségi gondolatok

Ha az első listaszint elemeiből hivatkozásokat csinálunk, megengedjük a tabstop használatát azon olvasók számára, akik nem használnak mutatóeszközöket. Ha sikerül olyan oldalakra mutatnunk, amik magasabb szinten vannak, mint az almenü elemei, az még jobb eredményt ad.

A szerzőkről

Patrick Griffiths egy szabadúszó londoni webtervező, aki kedveli, tiszteli a soul-t, az evolúciót és a kedves weboldalát (megjegyzés: az eredeti pet kedvencet és háziállatot egyaránt jelent), a HTML Dog-ot. Időnként becézgeti a PTG-t a hangulatától függően.

Dan Webb egy webtervező és DJ-nek is tanul. A korábbi munkái között szerepel szabványkövető, hozzáférhető oldalak és webalkalmazások megvalósítása az Egyesült Királyság kormányzati hivatalainak és emberek táncra penderítése London homályos szórakozóhelyein.


Translated with the permission of A List Apart Magazine and the author[s]. (Az A List Apart oldal és a szerző engedélyével lefordítva.)

Az eredeti cikk elérhető itt.