ugrás a tartalomhoz

Asztali és mobilmegjelenés szétválasztása

Pepita · 2013. Ápr. 29. (H), 15.46
Asztali és mobilmegjelenés szétválasztása

Egyre szélesedik a különféle hordozható eszközökkel szörfölők köre, ezért egy valamirevaló honlapnak megfelelő megjelenést kell biztosítania ezeken a – többnyire a monitoroknál jóval kisebb – megjelenítőkön is. Írásommal egy lehetséges megoldást mutatok be, ami talán sokaknak új és idegen lesz, viszont lévén sok más megoldási lehetőség is: követni nem kötelező, de mindenkinek tanulságos lehet.

Kezdetek

Eleinte én is – ahogy sokan mások – a link[media="handheld"] attribútummal operáltam, de hamar rá kellett jönnöm: ez nem a legjobb megoldás, mert nem minden mobileszköz használja megfelelően, illetve a mobilon nem megjelenítendő tartalmat is letölti a kliens, tehát a szűkös sávszélesség továbbra is problémát jelent.

Kicsit körülnéztem és azt láttam, hogy egyes honlapokon például m.example.com aldomainen szolgálják ki a mobilos látogatókat. Ezt sokszor összekötik egy user agent ellenőrzéssel, ami alapján – ha mobileszköz – átirányítanak az aldomainre. Ezt ma sem tartom egészen jó megoldásnak, mert szerintem egy honlap legyen egy domainen, illetve user agent kerülhet elő naponta is új, így az összehasonlításhoz szükséges adatbázist nagyon sűrűn kell(ene) frissíteni.

Ezek fényében lassan kialakult a koncepcióm:

  • Alapjában véve nem rossz dolog a user agent figyelése, de nem szabad mindent erre alapozni.
  • A látogatónak legyen lehetősége beavatkozni, ne döntsünk teljes mértékben helyette.
  • Ha a második pontot felhasználóbarát módon tudjuk kivitelezni, akkor már nem is olyan nagy baj, ha tévedünk a detektáláskor.
  • Azokat a tartalmi részeket, amelyeket a mobil-nézetben nem akarunk megjeleníteni, ne is küldjük ki a HTML-ben.
  • A honlap maradjon egy domainen, egyszerű, aránylag kevés munkát igénylő szoftver legyen (alacsony költség).
  • A megoldás újrahasznosítható legyen.
  • Természetesen mindkét megjelenítés alkalmazkodjon a többféle kijelzőmérethez.

A megoldás

Megelégedve használom a CodeIgniter keretrendszert, ezért most is ebben dolgozunk. A bemutatott példa eléggé egyszerűsített, szándékosan nem használunk most adatbázist és a HTML5/CSS3 lehetőségeit.

Először is sablonokra lesz szükségünk: desktop.php, mobile.php és menu.php. A menüt azért tesszük külön fájlba, hogy minden nézethez ugyanazt használhassuk.

Tegyük fel, hogy azt a feladatot kaptuk, hogy asztali nézetben képes fejléc, alatta menü, alatta három hasáb, alul pedig lábléc legyen. Valahol legyen üdvözlő üzenet, ha most érkezett a látogató. A mobilnézetet ránk bízták, annyi megkötéssel, hogy a jobb oldalsáv tartalma nem kell, de a középső és a bal hasábé igen, előbbi a fontosabb. Ezen túl szabad a gazda.

application/views/templates/desktop.php:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="hu">
    <head>
        <title><?= $title ?></title>
        <meta name="robots" content="<?= $robots ?>" />
        <meta name="keywords" content="<?= $keywords ?>" />
        <meta name="description" content="<?= $description ?>" />
        <link rel="shortcut icon" type="image/x-icon" href="<?= base_url() ?>favicon.ico" />
        <link rel="stylesheet" type="text/css" media="screen" href="<?= base_url() ?>public/css/desktop.css" />
        <?php if (!empty($js) || !empty($js2)): ?>
        <script type="application/javascript" src="<?= base_url() ?>public/js/jquery_14.js" />
        <?php endif ?>
        <?php if (!empty($js)): ?>
        <script  type="application/javascript" src="<?= base_url() ?>public/js/<?= $js ?>" />
        <?php endif ?>
    </head>
    <body>
        <div id="header">
            <p><a href="<?= base_url() ?>nezet/mobil">Mobil</a></p>
            <h1><?= $site_name ?></h1>
            <p><?= $slogan ?></p>
        </div>
        <?php if (!empty($message)): ?>
        <div id="message">
            <?= $message ?>
        </div>
        <?php endif ?>
        <div id="nav">
            <?php include 'menu.php' ?>
        </div>
        <div id="container">
            <div id="left">
                <?= $left ?>
            </div>
            <div id="content">
                <?= $content ?>
            </div>
            <div id="right">
                <?= $right ?>
            </div>
        </div>
        <div id="footer">
            <p>
                Futásidő: <strong><?= $elapsed_time ?></strong> s,
                Memória: <strong><?= $memory_usage ?></strong> KiB
            </p>
        </div>
        <?php if (!empty($js2)): ?>
        <script type="application/javascript" src="<?= base_url() ?>public/js/<?= $js2 ?>" />
        <?php endif ?>
    </body>
</html>

A sablon változóinak természetesen majd megfelelő értéket kell adnunk, ezt részben egy saját konfig fájlból fogjuk megtenni, másrészt ezekben lesznek a dinamikusan generált tartalmak is. A div#message-ben felhasználói üzeneteket fogunk megjeleníteni.

public/css/desktop.css:

body {
    margin: 0;
    padding: 0;
    overflow: auto;
    background-color: #fbf7eb;
    font-family: "Georgia", serif;
}

#header {
    width: 100%;
    background: url("fejlec_hatter.jpg") no-repeat center;
    height: 110px;
    overflow: hidden;
}

#message {
    width: 100%;
    background-color: #d5d5d5;
    color: #939a0a;
}

#nav {
    font-family: fantasy;
    font-variant: small-caps;
    padding-left: 201px;
    height: 26px;
    font-size: 16px;
    background-color: #d5d5d5;
}

#nav li {
    float: left;
    list-style: none;
    line-height: 26px;
    padding: 0 10px 0 10px;
}

#nav li:hover {
    background-color: #c3c3c3;
}

.active_menu {
    background-color: #fbf7eb;
    border: 1px solid #808080;
    border-bottom: none;
}

#container {
    width: 100%;
}

#left {
    position: absolute;
    left: 0;
    width: 200px;
    padding-bottom: 30px;
    border-right: 2px solid #d5d5d5;
    overflow: hidden;
}

#content {
    position: absolute;
    left: 200px;
    right: 200px;
    padding-bottom: 30px;
    border-right: 2px solid #d5d5d5;
    border-left: 2px solid #d5d5d5;
    overflow: visible;
}

#right {
    position: absolute;
    right: 0;
    width: 200px;
    padding-bottom: 30px;
    border-left: 2px solid #d5d5d5;
    overflow: hidden;
}

#footer {
    position: fixed;
    bottom: 0;
    width: 100%;
    height: 24px;
    border-top: 2px solid #d5d5d5;
    background-color: #ecd99d;
    line-height: 24px;
    font-family: sans-serif;
}

Ez csupán a dobozok és a menü stílusa, a többi elemé (címek, bekezdés stb.) többnyire relatív méretezésű (em, %).

Nézzük a mobil sablont!

application/views/templates/mobile.php:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="hu">
    <head>
        <title><?= $title ?></title>
        <meta name="robots" content="<?= $robots ?>" />
        <meta name="keywords" content="<?= $keywords ?>" />
        <meta name="description" content="<?= $description ?>" />
        <link rel="shortcut icon" type="image/x-icon" href="<?= base_url() ?>favicon.ico" />
        <link rel="stylesheet" type="text/css" media="screen" href="<?= base_url() ?>public/css/mobile.css" />
        <?php if (!empty($js) || !empty($js2)): ?>
        <script type="application/javascript" src="<?= base_url() ?>public/js/jquery_14.js" />
        <?php endif ?>
        <?php if (!empty($js)): ?>
        <script  type="application/javascript" src="<?= base_url() ?>public/js/<?= $js ?>" />
        <?php endif ?>
    </head>
    <body>
        <div id="header">
            <p><a href="<?= base_url() ?>nezet/asztali">Asztali</a></p>
            <h1><?= $site_name ?></h1>
        </div>
        <div id="message">
            <?= $message ?>
        </div>
        <div id="nav">
            <?php include 'menu.php' ?>
        </div>
        <div id="content">
            <?= $content ?>
        </div>
        <div id="left">
            <?= $left ?>
        </div>
        <div id="footer">
            <p>
                Futásidő: <strong><?= $elapsed_time ?></strong> s,
                Memória: <strong><?= $memory_usage ?></strong> KiB
            </p>
        </div>
        <?php if (!empty($js2)): ?>
        <script type="application/javascript" src="<?= base_url() ?>public/js/<?= $js2 ?>" />
        <?php endif ?>
    </body>
</html>

Itt container-re sincs szükségünk, mivel nem csinálunk hasábokat, hadd legyenek a dobozok minél szélesebbek. Vegyük észre, hogy a fejlécbe csak a főcímet (oldal neve) írjuk ki, a szlogent nem. Ezzel további helyet spórolunk, hogy minél kevesebbet kelljen görgetni. (Tegyük fel, hogy a megrendelő beleegyezett.)

public/css/mobile.css:

body {
    margin: 0;
    padding: 0;
    overflow: auto;
    background-color: #fbf7eb;
    font-family: "Georgia", serif;
}

#header {
    background: url("fejlec_hatter_mobil.png") repeat-x;
}

#message {
    width: 100%;
    background-color: #d5d5d5;
    color: #939a0a;
}

#nav {
    height: 20px;
    background-color: #d5d5d5;
    font-size: 12px;
    font-family: fantasy;
    font-variant: small-caps;
}

#nav li {
    float: left;
    padding: 0 4px 0 4px;
    list-style: none;
    line-height: 20px;
}

#left {
    width: 100%;
    border-top: 1px solid #d5d5d5;
    overflow: hidden;
}

#content {
    width: 100%;
    overflow: visible;
}

#footer {
    width: 100%;
    height: 16px;
    background-color: #ecd99d;
    border-top: 1px solid #d5d5d5;
    line-height: 16px;
    font-family: sans-serif;
}

Rövidebb lett a CSS is, a fejléc háttérképét lecseréltük egy egészen kicsire, amivel sávszélességet spórolunk. Mindkét sablon bal felső sarkában van a nézetváltó link: így görgetés nélkül azonnal látható. Már csak a menü van hátra:

application/views/templates/menu.php:

<ul>
    <li><a href="<?= base_url() ?>">Címlap</a></li>
    <li><a href="<?= base_url() ?>oldal/bongeszo">Böngésző</a></li>
    <li><a href="<?= base_url() ?>oldal/egyebek">Egyebek</a></li>
</ul>

Ennyi kód után azt is hihetnénk, hogy hátradőlhetünk, de nem így van. Most kezdhetünk gondolkodni azon, hogy mikor és hol (hogyan) kellene detektálni a böngészőeszközt. Kézenfekvő megoldásnak tűnne vezérlő előtti (pre controller) kampót (hook) használni, csakhogy van egy kis gond.

Úgy tudnánk kényelmesen megírni az osztályt, ha közben használhatnánk egy CI_Controller példányt is, ezen keresztül tudnánk betölteni és használni a szükséges session és user_agent osztályokat, valamint így tudunk közvetlenül vezérlő-adatokat létrehozni. Ehhez egy kicsit csalnunk kell: nem kampót írunk, hanem könyvtárat, amit az autoload.php megfelelő sorával fogunk betölteni.

$autoload['libraries'] = array('session', 'client_detect', 'parser');

A parser osztályt a vezérlőben fogjuk használni. A sorrend fontos, a session-t előbb töltjük be, mint a client_detect-et.

Ezeket az osztályokat a CI_Controller konstruktora tölti be, ezért az általunk írt vezérlő konstruktorában már elérhetjük, illetve módosíthatjuk a könyvtárunk által létrehozott adatokat, persze csak a parent::__construct(); sor után.

Szükségünk lesz még egy site.php nevű konfigurációs fájlra is, ebben tároljuk az alapértelmezett $title, $robots stb. értékeket:

<?php if (!defined('BASEPATH')) {
    exit('No direct script access allowed');
}

$config['def_title']       = 'Asztali-mobil megjelenítés';
$config['def_robots']      = 'all';
$config['def_keywords']    = 'mobilnézet, webdesign, webfejlesztés, mobileszköz';
$config['def_description'] = 'Asztali és mobilmegjelenés szétválasztása';
$config['site_name']       = 'Detektálás és választhatóság';
$config['def_slogan']      = 'Ez egy felhasználóbarát megoldás';
$config['welcome']         = '<h3>Üdvözöljük honlapunkon!</h3>';

Ezt a fájlt a $autoload['config'] = array('site'); sorral töltjük be, szintén az autoload.php-ben.

Mivel több egyidejű feladatunk is van az eszköz detektálásán kívül, ezeket is a Client_detect osztályban fogjuk megvalósítani.

application/libraries/Client_detect.php:

<?php if (!defined('BASEPATH')) {
    exit('No direct script access allowed');
}

class Client_detect {
    private $CI;
    
    public function __construct() {
        $this->CI =< get_instance();
        $this->CI->load->library(array('user_agent'));
        
        $this->Detect();
    }

A konstruktorban lekérjük a vezérlő referenciáját, majd ezzel betöltjük a user_agent osztályt, végül meghívjuk a detektáló függvényünket.

    private function Detect() {
        $this->CI->data['message'] = '';
        
        @$x = file_get_contents(APPPATH . 'data/db.dat');
        
        if ($this->CI->session->userdata('usercount') === false) {
            // Most jött hozzánk, mert nincs usercount
            if ($this->CI->agent->is_mobile()) {
                // Mobil v. asztali?
                $this->CI->session->set_userdata('platform', 'mobile');
            } else {
                $this->CI->session->set_userdata('platform', 'desktop');
            }
            
            if ($this->CI->agent->is_robot()) {
                // Robot, nem számoljuk
                $this->CI->session->set_userdata('usercount', $x);
            } else {
                // Nem robot, számoljuk
                
                $x += 1;
                @file_put_contents(APPPATH.'data/db.dat', $x);
                
                $this->CI->session->set_userdata('usercount', $x);
                $this->CI->session->set_userdata('welcome', true); // Máshol felhasználható
                $this->CI->data['message'] = config_item('welcome');
            }
        } else {
            // Már volt nálunk
            
            $this->CI->session->set_userdata('usercount', $x);
            $this->CI->session->unset_userdata('welcome');
        }
        
        $this->Data_fill();
    }

Itt a vezérlő $data tömbjét használjuk, ebben lesznek a nézet számára átadandó adatok, a vezérlőben majd kiegészítjük és továbbadjuk.

A $this->CI->session->userdata('usercount') a látogatók száma, ha ez nincs (false), akkor a látogató most érkezett. A 'platform' fogja tárolni a megjelenítő típusát, a 'welcome' pedig arra jó, ha esetleg a vezérlőben (vagy modellben) más műveletet is akarunk végezni új látogató érkezésekor (pl. cookie-login). Az üdvözlőüzenetet helyben beállítjuk.

A user_agent osztályhoz tartozó minták a user_agents.php-ben találhatók (config), mindenki tapasztalatai alapján bővítheti.

Végül ott egy $this->Data_fill() hívás: külön függvényben töltjük fel az alapértelmezett nézet adatokat, ezt a függvényt kell újrafelhasználáskor az adott honlapnak megfelelően átírnunk.

    private function Data_fill() {
        $this->CI->data['title']       = config_item('def_title');
        $this->CI->data['robots']      = config_item('def_robots');
        $this->CI->data['keywords']    = config_item('def_keywords');
        $this->CI->data['description'] = config_item('def_description');
        $this->CI->data['js2']         = ''; // Vezérlőben adjuk meg, ahol kell
        $this->CI->data['site_name']   = config_item('site_name');
        $this->CI->data['slogan']      = config_item('def_slogan');
        
        $this->CI->data['message'] .= $this->CI->session->flashdata('message');

        if ($this->CI->session->userdata('platform') == 'mobile') {
            $this->CI->data['js'] = 'mobile.js';
        } else {
            $this->CI->data['js'] = 'desktop.js';
        }
        
        $this->CI->data['left'] =
              '<h6>Bal box tartalma</h6>'
            . '<p>'
            . 'Látogatók száma:'
            . '<strong>'
            . $this->CI->session->userdata('usercount')
            . '</strong>'
            . '</p>'
            . '<p>Egyéb tartalom fantázia szerint.</p>'
        ;
        
        $this->CI->data['right'] = '<h6>Jobb box tartalma</h6><p>Akár reklámok/linkek is lehetnének.</p>';
    }
}

Itt most egy nagyon leegyszerűsített adatfeltöltés van, természetesen az oldalsávokba valamilyen feldolgozott tartalom kellene, amit – pl. ha oldalanként különböző – vezérlőben vagy modellben állítanánk elő, és ha lehet, cache-elnénk.

A $this->CI->session->flashdata('message')-et átírányításkor fogjuk használni felhasználói üzenet továbbítására. Fontos, hogy a $data['message'] csak detektáláskor lett beállítva, itt – és később vezérlőben – már hozzáfűzzük a további üzeneteket.

A $data['js']-t „játékból” állítjuk itt be, valójában inkább oldalanként különböző JavaScript csatolására hasznos. Ezt a két JS-t a sablonokban statikusan is megadhatnánk.

Detektáló osztályunk készen is van, szükségünk van még vezérlőre (Page), amit be is állítunk a routes.php-ben alapértelmezettnek: $route['default_controller'] = 'page';.

application/controllers/page.php:

<?php if (!defined('BASEPATH')) {
    exit('No direct script access allowed');
}

class Page extends CI_Controller {
    public function __construct() {
        parent::__construct();
        
        // Itt már manipulálhatjuk az adatokat:
        $this->data['message'] .= '<p>Üzenet átírva.</p>;
    }

Mint már említettem: a szülő konstruktora után már a Client_detect által létrehozott adatot manipulálhatjuk. Természetesen ilyen állandó üzenetre ritkán van szükség, de a többi adat érdekes lehet számunkra már a konstruktorban is.

Mivel ez az alapértelmezett vezérlőnk, célszerű egy index() függvényt készítenünk, ez szolgálja ki a főoldalt:

    public function index() {
        // Főoldal
        $this->data['content'] = $this->parser->parse('pages/front', array(), true);
        $this->view();
    }

A főoldal tartalma az application/views/pages/front.php fájlban van. Parser-t használunk, mert egyelőre változóba kell nekünk a tartalom, és mert annak ellenére is lehet a fájlban PHP kód, hogy csak üres adattömböt adtunk át.

Látható, hogy nem betöltöttük a view osztályt, hanem hivatkoztunk egy függvényünkre, tehát meg is kell írnunk:

    private function view() {
        // Mobil vagy asztali?
        if ($this->session->userdata('platform') == 'desktop') {
            $this->load->view('templates/desktop', $this->data);
        } else {
            $this->load->view('templates/mobile', $this->data);
        }
    }
}

Végre felhasználjuk a detektálás óta létező 'platform' session-adatot, ennek függvényében választunk a két (vagy akár több) sablonunk közül. Természetesen több függvényünk is szokott lenni a vezérlőben, ezért vettük külön ezt a függvényt.

Most még hátra van a kézi nézetváltás, aztán egy kis díszítés. Második vezérlőnk:

application/controllers/view.php:

<?php if (!defined('BASEPATH')) {
    exit('No direct script access allowed');
}

class View extends CI_Controller {
    public function __construct() {
        parent::__construct();
    }
    
    public function mobile() {
        if ($this->session->userdata('platform') == 'mobile') {
            $this->session->set_flashdata('message', '<p>Már mobil-nézetet használ.</p>');
        } else {
            $this->session->set_flashdata('message', '<p>Mobil nézet.</p>');
            $this->session->set_userdata('platform', 'mobile');
        }
        
        $this->generate();
    }
    
    public function desktop() {
        if ($this->session->userdata('platform') == 'desktop') {
            $this->session->set_flashdata('message', '<p>Már asztali-nézetet használ.</p>');
        } else {
            $this->session->set_flashdata('message', '<p>Asztali nézet.</p>');
            $this->session->set_userdata('platform', 'desktop');
        }
        
        $this->generate();
    }
    
    private function generate() {
        $referrer = $this->agent->referrer();
        
        if ($this->agent->is_referral() && mb_strpos($referrer, base_url()) === 0) {
            redirect($referrer, 'location', 302);
        } else {
            redirect(base_url(), 'location', 302);
        }
    }
}

Váltás végén egy átirányítással generáltatjuk újra az oldalt, ezért az üzenet továbbítására a Client_detect-ben látott 'message' flashdata-t használjuk.

A díszítést (JS) az így is nagy terjedelem miatt nem részletezném, asztali verzión az aktuális menühöz adjuk az active_menu osztályt; mobilon egy <select>-et készítünk a menüből, és végignézzük az <img>-ket, ha valamelyik szélesebb, mint a kijelző, akkor kicsinyítjük.

Ezzel a módszerrel lehet akár készülékenként eltérő designt is megvalósítani – kellőképpen bővített és karbantartott user_agents.php-vel –, de mindig tartsuk szemelőtt, hogy agent string-et hamisat is kaphatunk, és a felhasználónak is hagyjuk meg a könnyű, egyszerű választás lehetőségét!

Remélem kezdők, haladók és profik számára is hasznos volt egy egyéni(?) megoldásról olvasniuk, és azt is, hogy kedvet csináltam azok számára, akik még nem foglalkoztak mobilmegjelenéssel.

 
Pepita arcképe
Pepita
Horváth Péter webfejlesztő-programozóként dolgozik, főként adatbázis-tervezési és backend fejlesztési területen.
1

Gratulálok, szép írás.

Hidvégi Gábor · 2013. Ápr. 29. (H), 19.25
Gratulálok, szép írás.
2

Jó kis írás, "főleg kezdőknek

virág · 2013. Ápr. 30. (K), 07.32
Jó kis írás, "főleg kezdőknek jöhet jól" - gondolhatná az ember. :))) Aztán felmegy a mobiljával az index.hu-ra elolvasni a reggeli híreket és agyvérzés közeli állapotba kerül attól, hogy egy ekkora hírportálnak csapnivaló, idegőrlően ócska a mobilos megjelenése. Remélem az ottani fejlesztőcsapat is elolvassa ezt a kis, kezdőknek való cikket, hátha megtanulnak mobilra optimalizált megjelenést csinálni. Szóval a nevükben is köszönet a cikkért és amúgy is :)))
Én a CI-t nem nagyon szeretem, én inkább a Symfony-t használom, de ez részletkérdés, csak eszközök... szóval gratula a cikkhez, csak ennyit akartam. :)
3

Elgondolkoztató

blacksonic · 2013. Ápr. 30. (K), 08.20
Elgondolkoztató cikk, hogy reszponzív vagy különválasztott css sel dolgozzunk e.
Viszont a kódban a tipokat empty kulcsszavaknál, error suppression operatorokat, meg PHP stringben lévő HTML elemeket érdemes lenne kiszedni a példából.
4

Köszönök minden véleményt,

Pepita · 2013. Ápr. 30. (K), 20.57
a pozitívakból és negatívakból is igyekszem levonni a megfelelő tanulságokat.
Remélem az ottani fejlesztőcsapat is elolvassa ezt a kis, kezdőknek való cikket
Én nem csak kezdőknek szántam, és nem is mondanám senkire, hogy kezdő, mert ezt vagy azt nem nekem tetszően valósít meg - természetesen ettől még lehet igazad. :)
error suppression operatorokat, meg PHP stringben lévő HTML elemeket érdemes lenne kiszedni a példából.
Miért? Mi a fontosabb / jobb megoldás (éles honlapon): a látogatóid számának esetleges ki nem írása, vagy az, hogy kiírjunk helyette (és a kért tartalom helyett) egy hibaüzenetet, esetleg a "nagy fehér semmit"?

Persze bele lehetne itt is mélyedni mindenféle résztartalmak legyártásába, cache-elésbe, optimalizációba, csak akkor el is veszne a rengeteg bába közt a gyerek, ezért
Itt most egy nagyon leegyszerűsített adatfeltöltés van, természetesen az oldalsávokba valamilyen feldolgozott tartalom kellene, amit – pl. ha oldalanként különböző – vezérlőben vagy modellben állítanánk elő, és ha lehet, cache-elnénk.

Nem mondom, hogy nincs igazad, de ezek nélkül a "hibák" nélkül csak lényegesen nagyobb terjedelemben tudtam volna megírni - ugyanennyi hasznos tartalom mellett. Szerintem ez rossz arány.
5

Nem egészen

blacksonic · 2013. Május. 6. (H), 16.52
Két különböző dolog, hogy egy példába raksz-e hibakezelést, vagy rossz példát mutatsz az error supression operátorral.
Miért? Mi a fontosabb / jobb megoldás (éles honlapon): a látogatóid számának esetleges ki nem írása, vagy az, hogy kiírjunk helyette (és a kért tartalom helyett) egy hibaüzenetet, esetleg a "nagy fehér semmit"?

Ez csak egy példaprogram, nem hiszem hogy hibakezeléssel itt kellene foglalkozni...meg lehet oldani hogy ha nem kritikus a hiba abból a felhasználó ne vegyen észre semmit (pl. notice esetén ne legyen fehér képernyő).
6

szerintem

zzrek · 2013. Május. 6. (H), 18.51
Szerintem nem olyan nagy baj, ha egy példakódban az error supression operátorral egyszerűsítik le a felépítést, mivel egyből kiszúrható, hogy ott van valami, amivel még foglalkozni kell/lehet programozási cél, stílus, vérmérséklet vagy elegancia alapján, kinek mi tetszik.
Persze az sem baj, ha megemlíted, hogy szerinted az nem jó példa.
:-)
7

Én személy szerint képtelen

bamegakapa · 2013. Május. 6. (H), 19.45
Én személy szerint képtelen vagyok komolyan venni példakódot, ami tele van szórva kukacokkal. Jobb lenne, ha a kezdők nem is hallanának erről a lehetőségről.
8

ctrl c ctrl v

blacksonic · 2013. Május. 6. (H), 20.31
sajnos a példakódok sokszor copy pastelve kerülnek be, akik tanulnak ezt elfogadottnak vehetik emiatt
így a tanítás mellett árthat is az ilyen kód
9

Pontosan. Részemről

bamegakapa · 2013. Május. 6. (H), 21.12
Pontosan. Részemről betiltanám a @ operátort :). De minimum, hogy ne alkalmazzuk példakódokban. Annó kezdőként nekem is fájdalmas volt megtanulni, miért is ne használjam, és azóta is szívtam már be vele, amikor hibát kerestem valaki más kódjában.

Csak példaként, kinek melyik tetszene jobban (példakódban persze, éles kódban egyik se):
@$x = file_get_contents(APPPATH . 'data/db.dat');
vagy
//TODO: hibaellenőrzés! (fájl nem létezik, nem olvasható, tartalma nem szám)
$x = file_get_contents(APPPATH . 'data/db.dat');
A kukacos verzióban ráadásul a szerencsétlen kezdő ha ki is próbálja a kódot, és nem számol neki semmit se, akkor az életben ki nem találja, mi a probléma, mert nincs hibaüzenet.
10

Srácok, nem értettétek

Pepita · 2013. Május. 6. (H), 22.04
Srácok, nem értettétek meg a cikk mondanivalóját. Megjelenésről (view) szól, nem fájlkezelésről és pláne nem látogatottságról. Ez utóbbi kettőről cikksorozatot lehetne írni, a kukacról nem is beszélve... Innentől ez már puszta kötöszködés a részetekről, nem visz előbbre senkit. A kezdők kedvéért jó, hogy blacksonic "kolléga" jelezte (hangsúlyozta) ezeket a dolgokat, de felesleges rajta tovább lovagolni.

Megjegyzem, hogy a használt keretrendszernek megvannak a saját fájlkezelő függvényei és hibakezelése is. (És nem teljesen @mentes.:)) Viszont azt sem akartam, hogy azok (az esetleg kezdők), akik még sose látták a CodeIgniter-t, abszolút semmit se értsenek belőle, illetve haladók is csak CI-ben tudják hasznosítani (mondjuk egy rakás beállítás szintén nincs a cikkben, tehát nemigazán tudod egy az egyben másolni).

A megjegyzésbe írt tennivaló - hát igencsak kutya vacsorája. Vagy odaírod a teljes kódot, vagy a cikk szövegében jelzed, hogy ez nem teljes. (Mint ahogy én is tettem.)

Ha már ennyire megmondjátok, hogy hogyan kell jó cikket írni, belinkelhetnétek néhány saját példátokat is, hátha tanulok belőle. Itt a WL-en van valami?
11

Nincs értelme kritikán

bamegakapa · 2013. Május. 7. (K), 10.00
Nincs értelme kritikán megsértõdni, nem azért írjuk.

Még pár szó a témához: mivel úgyis odaírtad, hogy nem teljes, akkor már inkább ne rakd ki a kukacot. Nem megoldás, problémaforràs. Ez meg most csak kérés, figyelmen kívül lehet hagyni.
13

Dehogy

Pepita · 2013. Május. 9. (Cs), 19.58
Dehogy sértődtem meg, ne viccelj már! Csak jeleztem, hogy túl lett lihegve már. De kettőtök (és persze a helyesség) kedvéért igyekszem a jövőben "kukactalan" cikke(ke)t írni. :)
12

Nincs értelme

blacksonic · 2013. Május. 7. (K), 12.16
csak segíteni akartunk, mint írtam, maga a cikk tetszett, és utána írtam 1-2 dolgot aminek a javításával jobbá lehetne tenni a cikket
18

Debug szempontjából nagyon

inf · 2013. Júl. 3. (Sze), 13.50
Debug szempontjából nagyon durván rossz a @ operátor. Akkor már az is jobb, ha nincs hibakezelés, aztán fehér képernyő, log fájl... Legalább kiderül, hogy mi a hibája...
14

Mennyire van jogosultsága

MadBence · 2013. Május. 11. (Szo), 21.19
Mennyire van jogosultsága ennek a három sablonnak? Háromszor annyi kódot kell karbantartani. Az igazán szép megoldás nem a useragent detektálása, hanem a kliens képernyőméretének megfelelő megjelenés kiválasztása (ez pl egy az egyben megoldható CSS-ből).
Ha a felhasználó "váltani" akar az egyes megjelenítési formák között, az azt jelenti, hogy amit ráerőltettünk, az rossz, és nem az a megoldás, hogy váltani engedjünk, hanem az, hogy kijavítjuk a hibákat.
15

Sokrétűbb

vbence · 2013. Május. 12. (V), 09.09
A probléma ennél nagyságrendekkel sokrétűbb. A felbontás vajmi keveset mond a médiumról. Én most egy 15.5 inches monitor előtt ülök 1280x800-as felbontással. Egy HTC One 4.7 inchen ad 1920x1080-at. - Szerintem könnyen belátható, hogy a pixelméret rossz indikátor.

(És még nem beszéltünk az 55 inches, szintén 1920x1080-as smart LCD TV-ről, amin igenis böngésznek néhányan.)

Az eszményi megoldás a képernyő való élet beli méretének függvényében lenne kialakítható (15" vs 4.7"), összekötve pár fontos feature-rel (pl touch interfész vagy egér-e a preferált az adott platformon), de ezt az információt egyik platform tulajdonosa sem igyekszik az orrunkra kötni.

Amíg ez nem lesz elérhető, maradnak a barkácsmegoldások (teljesen pozitív értelemben).
16

Jogos, erre nem gondoltam.

MadBence · 2013. Május. 12. (V), 14.21
Jogos, erre nem gondoltam. Ettől függetlenül biztosan lehet még egyéb metrikák alapján behatárolni az eszközt, hiszen ez lenne a media query-k dolga. Illetve ha ez jelenleg nem megoldható, akkor fel kell készülni, hogy valószínűleg ez lesz a sztenderd megoldás ilyen téren.
19

Azért egy mobilon sok esetben

inf · 2013. Júl. 3. (Sze), 13.55
Azért egy mobilon sok esetben csak jóval kisebb sávszélesség érhető el, mint asztali géppel (még egyáltalán nincs kiépítve a 4g), szerintem jobb mobilra külön megoldást írni, ami ezt figyelembe veszi.
20

Nem tudod

Poetro · 2013. Júl. 3. (Sze), 14.21
Sajnos nem tudod, hogy az illető készülékén milyen a sávszélesség. Lehet publikus WiFi-t használ, lehet, hogy otthon van a nagy sávszélességű WiFi-jén.
21

Ja hát itt csak az lenne

inf · 2013. Júl. 3. (Sze), 14.33
Ja hát itt csak az lenne megoldás, ha a böngésző elküldené a dpi-t, a felbontást meg a sávszélességet, aztán lehetne kalkulálni vele... Az előbbi kettő már megy, az utóbbi egy érdekes kérdés.
22

Érdekes

vbence · 2013. Júl. 3. (Sze), 14.38
Wow... Hogyan tudod meg a DPI-t?
23

Például media query-vel.

Joó Ádám · 2013. Júl. 3. (Sze), 15.05
Például media query-vel.
24

Azonbelül?

vbence · 2013. Júl. 4. (Cs), 09.15
Én nemrég vizsgálódtam az ügyben, és semmi nyomát nem találtam annak, hogy maga a DPI vagy a kijelző fizikai mérete (amit aztán leoszthatnánk a valós vagy hazudott pixelmérettel) elérhető lenne akár CSS akár JS alapon.
25

matchMedia

T.G · 2013. Júl. 4. (Cs), 09.32
Elvileg lenne megoldás, de a támogatottság elég sovány...

window.matchMedia("(resolution: 96dpi)").matches
window.matchMedia("(min-resolution: 72dpi)").matches
...
26

Esetleg egy olyan megoldás,

Joó Ádám · 2013. Júl. 4. (Cs), 20.45
Esetleg egy olyan megoldás, amiben egy elemre beállítasz egy fizikai méretet, majd lekérdezed a pixelben vettet, és leosztasz?
27

Proci

Pepita · 2013. Júl. 5. (P), 00.45
Szerintem ez egy érdekes vonal, viszont minél több JS / egyéb futtatással kérdezgetünk, annál nagyobb lesz a processzorterhelés, így az akksi is jobban merül. Igazán tökéletes megoldás jelenleg - szerintem - nincs, az én elvem az, hogy minden erőforrással lehetőleg spórolni a kliensoldalon. Persze ez nem mehet a felhasználói élmény rovására.

Viszont egy egyszerű és jó módszer nagyon érdekelne sávszélesség becslésére, mert mindig arra készülni, hogy lehet, hogy csak 10kbps - hát elég nehéz (ha nem lehetetlen) feladat.
28

Azért beállítani egy elem

Joó Ádám · 2013. Júl. 5. (P), 01.45
Azért beállítani egy elem méretét egy centire, és lekérdezni a width tulajdonságát talán nem terheli meg olyan nagyon a processzort :)
31

Az nem, de

Pepita · 2013. Júl. 7. (V), 14.36
ha utána szintén JS-el kezded átvariálni a kinézetet, stb., az már felettébb gond lehet. Pl. egy sokképes galériánál mind a 40 bélyegképet kicsinyíteni... - na jó, ez erős túlzás, eleve "nem való" egy galériába 40 képet tenni.

De hamár dpi-t szeretnél megtudni, akkor miért egy centire állítasz, miért nem 1 inch? :) (Látod, hogy többet akarod számoltatni azt a szegény procit?! :))
32

Megteheted azt, hogy az első

Joó Ádám · 2013. Júl. 7. (V), 15.06
Megteheted azt, hogy az első kéréskor kiszámolod, visszaküldöd, eltárolod munkamenetben, és onnantól annak megfelelően szolgálsz ki.
33

Igen, abból lesz

Pepita · 2013. Júl. 8. (H), 02.46
Igen, abból lesz az 5 template 2 helyett... De nem feltétlenül, mindegy, zűrös ez már ilyenkor...
29

Át kell vinni bizonyos

inf · 2013. Júl. 5. (P), 09.36
Át kell vinni bizonyos mennyiségű adatot, aztán lemérni, hogy mennyi idő. Máshogy nem lehet. Minél kevesebb az adat, annál pontatlanabb, minél több az adat, annál többet kell várni, ha kicsi a sávszélesség. Ez kb olyan a webprogramozásban, mint a részecskefizikában a Heisenberg féle határozatlansági reláció. :P

Ugye amíg nincs meg a mérés addig nem tudsz tartalmat betölteni, szóval még a háttérbe se lehet rakni... Ha már ilyen van, kitennék valami választót az oldalra (hasonlót, mint a nyelv választó), ahol gyorsan lehet váltani az egyes nézetek között, a választást meg cookie-val megjegyezné. Alapból a handheld mobilos nézetet kapna kis sávszéllel, de ha még nincs cookie, akkor kiírná az oldalra, hogy bármikor lehet választani a másik nézetet a jobb felső sarokban lévő füllel.
30

Bal felső :)

Pepita · 2013. Júl. 7. (V), 14.30
Ez a tartalommérés nekem is eszembe jutott már, csak az vele a gond, hogy:
- Azt a tartalmat nem engedheted cache-elni (különben ugye kb. 0 lesz az idő;
- Ha mozgásban van az illető (pl. járművön utazik), ingadozik (nagyon) a sávszél, minden kéréskor meg mérni és átlagolni - hát nem tudom.

A választást én - ha csak tehetem - bal-felülre teszem, mert ha túl kicsi a kijelző, a vízszintes görgetést utálja legjobban a Júzer.

Egyelőre maradok a detektálásnál és váltási lehetőségnél, ha végre elkészül az új oldalam, ott megvillogtatom a váltólinket, ha adott méretnél (px) kisebb a kijelző és mégis "asztalit" kapott. A sütin is gondolkodtam már, de egyelőre maradok a session-nél, de már hajlok a soká lejáró süti felé, főleg, hogy te is írtad.
17

Három sablon?

Pepita · 2013. Május. 12. (V), 20.04
A képernyőméret kapcsán vbence-vel értek egyet, csak kicsit másként fogalmaznék, ill. próbálok konkrétabban válaszolni.
Mennyire van jogosultsága ennek a három sablonnak?
Itt két sablon van, gondolom a menüt számolod harmadiknak, de az mindkét sablon eleme. Ha így már háromnak számoljuk, akkor az egyes oldalak tartalma (css-el) is egy-egy sablonnak számít, tehát több. Ha css-ben fel akarsz készülni az "összes" képernyőméretre, az sokkal nagyobb karbantartási igényű lesz, mint két sablon, hiába van mondjuk egy fájlban (az pedig megint kérdéses, hogyha nekem egy kijelzőméretrem van, akkor minek töltsem le 10 másik css-ét).

Mint írtam is, a user agent detektálás önmagában kevés, mégis jóval többet lehet vele kezdeni, mint pl. a kijelző pixelméretével. És még ha ez a css megoldás jó lenne (nem az!), akkor is ottmaradt a feleslegesen kiküldött adatok problémája: attól, hogy pl. jónéhány képet display: none-al "eltüntetsz", még kiküldöd mint adatot, sőt, ugyanúgy letölti (és cache-eli) aképeket, tehát feleslegesen fogtad a sávszélességét is. Emiatt mindenképp érdemes a szerveroldalon (is) különválasztani az eszközöket, legalább kétfelé.

Ha a felhasználó "váltani" akar az egyes megjelenítési formák között, az azt jelenti, hogy amit ráerőltettünk, az rossz,...
Na, itt már elvi szinten sem értünk egyet. Kifejezetten az a rossz, ha ráerőltetsz bármit is a látogatódra. Javasolni kell az általad optimálisnak ítélt megoldásokat, de erőltetni semmit sem szabad. Ez a rossz megoldás - a lehetséges változatok közül pedig hagyni kell dönteni is a felhasználót. Ha lehetséges volna 100% pontossággal user agent-el detektálni, én akkor is kitennék linket v. más választási lehetőséget. Szerintem ez így helyes.
34

Szerintem a legjobb példa a

MadBence · 2013. Júl. 8. (H), 07.58
Szerintem a legjobb példa a helyes megvalósításra a smashingmagazine.com honlapja, a képernyő méretétől függően 5 féle elrendezést figyeltem meg. Nem lehet önkényesen váltani, mert nem is kell, hiszen az adott méretre tervezett dizájn azon a felbontáson kényelmes, a kisebb/nagyobb képernyősek pedig nem, így értelmetlen lenne a váltás.
35

Nem rossz példa

Pepita · 2013. Júl. 10. (Sze), 02.53
az adott méretre tervezett dizájn
Ez viszon azt feltételezi, hogy
- Már most tudod, hogy a jövőben milyen kijelzőket fognak gyártani és akár 15 féle design-t is hajlandó vagy (megfizetik) készíteni; vagy
- Folyamatos fejlesztési (anyagi) keret biztosított a honlap karbantartására.

"Nagyobbacska" megrendelők esetében ez lehet helyes és kifizetődő út, ám sajnos nekem még nem volt ilyenem... :)

Ezzel együtt a példa jó.
36

responsive

szörf kölcsönzés · 2013. Okt. 12. (Szo), 22.04
És wordpressben is bele lehet nyúlni a sablon szerkesztésébe ? A *** tanfolyam oldal sablonja tetszik csak nem tudom bele lehet-e nyúlni? Üdv:Timi

Hirdetés törölve. – Joó Ádám
37

Ez egy rövidéletű

Joó Ádám · 2013. Okt. 12. (Szo), 22.14
Ez egy rövidéletű regisztráció volt.
38

:-)

Pepita · 2013. Okt. 13. (V), 00.16
Hogy mik vannak...
39

bbproduction

Pepita · 2016. Május. 10. (K), 20.30
Kedves bbproduction!

Ne haragudj, de nem szoktam privát mailen egyes emberek problémáival ismeretlenül foglalkozni, szabad időmben szívesen segítek itt, a WL fórumon. (Ha tudok)
Kérlek nyiss a kérdésednek egy új témát.
Ennek előnyei:
- valószínűleg fogok reagálni
- más is reagálhat, akár jobb ötlettel is, mint én
- a kérdés és a válaszok nyilvánosak, így más is tud belőle tanulni
- legalább annyit fejlődni fogsz, hogy hogyan tudsz jól kérdezni (bocs, de ezt pláne nincs türelmem emailen írni)

Jó lenne, ha a kérdés nem az lenne, hogy "404 et kapok, vmi ötlet? " mert erre Kb az a válasz, hogy "ne nyisd meg ezt az urlt, akkor nincs 404" .

Sok sikert.

Update: @Ádám, ha lesz új fórum téma erről, kérlek töröld ezt a kommentet, igazából nem ide való.
40

Ezt mondjuk írhattad volna

Joó Ádám · 2016. Május. 11. (Sze), 00.24
Ezt mondjuk írhattad volna neki válaszlevélben, én is úgy szoktam.