Контроллерны куйгач, сез төймәләрне чистартасыз, таякларны күчерәсез, триггерларны тартасыз ... һәм уйлап табучы буларак, сез аның берсен дә күрмисез. Браузер аны ала, әлбәттә, ләкин консолга номер кертмәсәгез, ул күренми. Бу Gamepad API белән баш авырту. Бу еллар дәвамында булды, һәм ул бик көчле. Сез төймәләрне, таякларны, триггерларны, әсәрләрне укый аласыз. Ләкин күпчелек кеше аңа кагылмый. Нигә? Чөнки кире элемтә юк. Төзүче коралларында панель юк. Контроллерның сез уйлаганны эшләгәнен белү өчен ачык ысул юк. Ул сукыр очкан кебек тоела. Бу мине бераз корал төзергә этәрде: Gamepad Cascade Debugger. Консоль чыгышына карап тору урынына, контроллерның турыдан-туры, интерактив күренешен аласыз. Берәр нәрсәне басыгыз һәм ул экранда реакцияләнә. Cәм CSS Каскад Катламнары белән стильләр тәртиптә кала, шуңа күрә төзәтү чистарак. Бу язмада мин сезгә ни өчен контроллерны көйләү шундый авырту, CSS аны чистартырга ничек ярдәм итәчәген һәм үз проектларыгыз өчен кабат кулланыла торган визуаль дебугер төзи алуыгызны күрсәтермен.
Аларның барысын да кертә алсагыз да, тиз укылмый торган консол спам белән тәмамланырсыз. Мәсәлән: [0,0,1,0,0,0.5,0, ...] [0,0,0,0,1,0,0, ...] [0,0,1,0,0,0,0, ...]
Кайсы төймәгә басылганын әйтә аласызмы? Бәлки, ләкин күзләрегезне кысып, берничә керемне югалтканнан соң гына. Димәк, юк, керемнәрне укуга килгәндә төзәтү җиңел булмый. 3-нче проблема: структураның булмавы Тиз визуализаторны бергә ыргытсагыз да, стильләр тиз бозылырга мөмкин. Килешү, актив һәм төзәтү халәтләре бер-берсенә капланырга мөмкин, һәм ачык структурасыз, сезнең CSS ватык һәм киңәйтү авыр була. CSS Каскад катламнары ярдәм итә ала. Алар стильләрне өстенлек буенча заказланган "катламнарга" төркемлиләр, шуңа күрә сез спецификация белән көрәшүне туктатасыз һәм "Нигә минем төзәтү стилем күрсәтелми?" Киресенчә, сез аерым борчылулар саклыйсыз:
Базасы: Контроллерның стандарт, башлангыч күренеше. Актив: басылган төймәләр һәм күчерелгән таяклар өчен моментлар. Дебу: төзүчеләр өчен өстәмәләр (мәсәлән, санлы уку, кулланмалар һ.б.).
Әгәр дә без CSS катламнарын шуңа карап билгеләргә тиеш булсак, бездә: / * иң түбән өстенлеккә * / @ плейер базасы, актив, төзәтү;
@layer base { / * ... * / }
@layer актив { / * ... * / }
@layer debug { / * ... * / }
Eachәр катлам алдан әйтелгәнгә күрә, сез һәрвакыт кагыйдәләрнең җиңүен беләсез. Бу алдан әйтеп була, төзәтүне җиңеләйтеп кенә калмый, ә чынлап та идарә итә. Без проблеманы (күзгә күренми торган, тәртипсез кертү) һәм алымны (Каскад катламнары белән төзелгән визуаль төзәтүче) яктырттык. Хәзер без төзәтүче төзү өчен этаплап йөриячәкбез. Дебугер концепциясе Яшерен керүне күренү өчен иң җиңел ысул - аны экранга тарту. Бу төзәтүче шулай эшли. Кнопкалар, триггерлар, джойстиклар барысы да визуаль.
А басыгыз: Түгәрәк кабызыла. Таякны кадаклагыз: Түгәрәк әйләнә. Триггерны ярты юлга тарт: Бар ярты юлны тутыра.
Хәзер сез 0 һәм 1сларга карамыйсыз, ләкин контроллерның турыдан-туры реакциясен карау. Әлбәттә, дефолт, басылган, төзәтү мәгълүматлары кебек дәүләтләрдә туплана башлагач, бәлки хәтта язу режимы да CSS зурайганнан-катлаулана башлый. Менә каскад катламнары файдалы. Менә түбәндәге мисал: @layer base { .буттон { фон: # 222; чик-радиус: 50%; киңлеге: 40px; биеклеге: 40px; } }
@layer актив { .button.pressed { фон: # 0f0; / * ачык яшел * / } }
@layer debug { .буттон :: соң { эчтәлек: attr (мәгълүмат-кыйммәт); шрифт зурлыгы: 12px; төс: #fff; } }
Катлам тәртибе мөһим: база → актив → төзәтү.
база контроллерны сыза. басылган хәлләрне актив эшкәртә. каплауга ташлау.
Моны бозу - сез сәер спецификация сугышлары белән көрәшмисез дигән сүз. Eachәр катламның үз урыны бар, һәм сез нәрсә җиңгәнен һәрвакыт беләсез. Аны төзү Башта экранда нәрсәдер алыйк. Яхшы күренергә кирәкми - бары тик булырга тиеш, шуңа күрә бездә эшләргә кирәк.
Геймпад Каскад Дебугер
Бу туры мәгънәдә сандыклар. Әле дулкынландыргыч түгел, ләкин соңрак CSS һәм JavaScript белән тотып алу өчен тоткалар бирә. Ярар, мин монда каскад катламнарын кулланам, чөнки ул күбрәк штатлар өстәгәннән соң әйберләрне тәртиптә тота. Менә тупас юл:
/ * =================================== CASCADE LAYERS SETUP Заказ бирү мөһим: база → актив → төзәтү =================================== * /
/ * Катлам тәртибен алдан билгеләгез * / @ плейер базасы, актив, төзәтү;
/ * 1 нче кат: төп стильләр - килешү күренеше * / @layer base { .буттон { фон: 3333; чик-радиус: 50%; киңлеге: 70px; биеклеге: 70px; күрсәтү: флекс; аклау-эчтәлек: үзәк; тигезләү әйберләре: үзәк; }
.pause { киңлеге: 20px; биеклеге: 70px; фон: 3333; күрсәтү: сызык-блок; } }
/ * 2 нче кат: Актив хәлләр - басылган төймәләрне эшкәртә * / @layer актив { .button.active { фон: # 0f0; / * Басылганда ачык яшел * / үзгәртү: масштаб (1,1); / * Кнопканы бераз киңәйтә * / }
.pause.active { фон: # 0f0; үзгәртү: масштаб Y (1.1); / * Басылганда вертикаль сузыла * / } }
/ * 3 нче кат: Дебу каплаулары - уйлап табучы турында мәгълүмат * / @layer debug { .буттон :: соң { эчтәлек: attr (мәгълүмат-кыйммәт); / * Сан кыйммәтен күрсәтә * / шрифт зурлыгы: 12px; төс: #fff; } }
Бу ысулның матурлыгы - һәр катламның ачык максаты бар. Төп катлам беркайчан да активны кире кага алмый, һәм активлык, конкретлыкка карамастан, төзәтүне беркайчан да кире кага алмый. Бу CSS специфик сугышларын юкка чыгара, гадәттә көйләү коралларын җәберли. Хәзер кайбер кластерлар караңгы фонда утырган кебек. Дөресен генә әйткәндә, бик начар түгел.
JavaScript өстәү JavaScript вакыты. Монда контроллер нәрсәдер эшли. Без бу адымны төзиячәкбез. 1 адым: Дәүләт белән идарә итү Беренчедән, төзәтүче торышын күзәтү өчен безгә үзгәрешләр кирәк: // =================================== // Дәүләт белән идарә итү // ===================================
йөгерергә = ялган; // Дебугерның актив булу-булмавын күзәтә rafId булсын; // Бетерү өчен сорауAnimationFrame ID саклый
Бу үзгәрүчәннәр анимация циклын контрольдә тоталар, алар уен уенын кертүне өзлексез укыйлар. 2 адым: DOM сылтамаларын кулга алыгыз Алга таба, без яңартачак барлык HTML элементларына сылтамалар алабыз: // =================================== // ДОМ ЭЛЕМЕНТЛАРЫ // ===================================
const btnA = document.getElementById ("btn-a"); const btnB = document.getElementById ("btn-b"); const btnX = document.getElementById ("btn-x"); const pause1 = document.getElementById ("пауза1"); const pause2 = document.getElementById ("пауза2"); const статусы = document.getElementById ("статус");
Бу сылтамаларны фронтта саклау DOM-ны кат-кат сораудан эффективрак. 3 адым: Клавиатураның кире кайтуын өстәгез Физик контроллерсыз сынау өчен, без клавиатура төймәләрен төймәләргә картаячакбыз: // =================================== // Клавиатура төшүе (контроллерсыз сынау өчен) // ===================================
const keyMap = { "a": btnA, "б": btnB, "x": btnX, "p": [пауза1, пауза2] // 'p' ачкычы пауза барларын да контрольдә тота };
Бу безгә клавиатурадагы төймәләрне басып UI сынап карарга мөмкинлек бирә. 4 адым: Төп яңарту әйләнәсен ясагыз Менә тылсым кайда була. Бу функция өзлексез эшли һәм уен уенын укый: // =================================== // Төп Геймпадны яңарту // ===================================
функцияне яңартуGamepad () { // Барлык тоташтырылган уен уеннарын алыгыз const gamepads = navigator.getGamepads (); if (! gamepads) кайтса;
// Беренче тоташтырылган уен уенын кулланыгыз const gp = уен уеннары [0];
if (gp) { // "Актив" классны алыштырып яңарту төймәсе btnA.classList.toggle ("актив", gp.buttons [0]. басылган); btnB.classList.toggle ("актив", gp.buttons [1]. басылган); btnX.classList.toggle ("актив", gp.buttons [2]. басылган);
// Пауза төймәсен эшләгез (күпчелек контроллерларда 9 индекс) const pausePressed = gp.buttons [9]. басылган; pause1.classList.toggle ("актив", пауза басылган); pause2.classList.toggle ("актив", пауза басылган);
// Статус күрсәтү өчен хәзерге вакытта басылган төймәләр исемлеген төзегез басылсын = []; gp.buttons.forEach ((btn, i) => { if (btn.pressed)press.push ("төймә" + i); });
// Әгәр дә төймәләр басылса, статус текстын яңарту if (press.length> 0) { status.textContent = "Басылган:" + басылган.join (","); } }
// Дебугер эшләсә, циклны дәвам итегез if (йөгерә) { rafId = сорауAnimationFrame (яңартуGamepad); } }
ClassList.toggle () ысулы актив классны өсти яки бетерә, төймә басылганмы-юкмы, бу безнең CSS катлам стильләрен этәрә. 5 адым: Клавиатура вакыйгаларын эшләгез Бу вакыйганы тыңлаучылар клавиатураны кире кайтаралар: // =================================== // Клавиатура вакыйгалары куллары // ===================================
document.addEventListener ("ачкыч", (e) => { if (keyMap [e.key]) { // Бер яки берничә элемент белән эшләгез if (Array.isArray (keyMap [e.key])) { keyMap [e.key] .forEach (el => el.classList.add ("актив")); } else { keyMap [e.key] .classList.add ("актив"); } status.textContent = "Ачкыч басылган:" + e.key.toUpperCase (); } });
document.addEventListener ("ачкыч", (e) => { if (keyMap [e.key]) { // Ачкыч чыкканда актив халәтне бетерегез if (Array.isArray (keyMap [e.key])) { keyMap [e.key] .forEach (el => el.classList.remove ("актив")); } else { keyMap [e.key] .classList.remove ("актив"); } status.textContent = "Ачкыч чыгарылган:" + e.key.toUpperCase (); } });
6 адым: Башлау / Контрольне туктату Ниһаять, безгә төзәтүчеләрне кабызу һәм сүндерү ысулы кирәк: // =================================== // ДЕБУГГЕРНЫ ЯШ ON / ӨЧЕН // ===================================
document.getElementById ("күчү"). addEventListener ("басыгыз", () => { йөгерү =! йөгерү; // Эшләү халәтен борыгыз
if (йөгерә) { status.textContent = "Дебугер эшли ..."; updateGamepad (); // Яңарту әйләнәсен башлау } else { status.textContent = "Дебугер актив түгел"; CannAnimationFrame (rafId); // циклны туктатыгыз } });
Әйе, төймәгә басыгыз һәм ул ялтырый. Таякны этегез һәм ул хәрәкәтләнә. Бу. Тагын бер нәрсә: чимал. Кайвакыт сез утны түгел, саннарны күрергә телисез.
Бу этапта сез күрергә тиеш:
Экрандагы гади контроллер, Алар белән аралашканда реакцияләнгән төймәләр, һәм Басылган төймә күрсәткечләрен күрсәтүче өстәмә төзәтүне уку.
Моны азрак абстракт итәр өчен, монда экрандагы контроллерның реаль вакытта реакциянең тиз демо:
Хәзер, Старт язуны басу, Язуны туктатканчы, барысы да теркәлә. 2. CSV / JSONга мәгълүмат экспортлау Бүрәнәбез булганнан соң, без аны сакларга теләрбез.
1 адым: Йөкләү ярдәмчесен булдыр Беренчедән, безгә браузерда файл йөкләүләрне эшкәртүче ярдәмче функциясе кирәк: // =================================== // Ярдәмчене йөкләү // ===================================
downloadFile функциясе (файл исеме, эчтәлек, тип = "текст / гади") { // Эчтәлектән блок ясагыз const blob = яңа Blob ([эчтәлек], {тип}); const url = URL.createObjectURL (блок);
// Вакытлыча йөкләү сылтамасын төзегез һәм басыгыз const a = document.createElement ("а"); a.href = url; a.download = файл исеме; a.click ();
// Йөкләгәннән соң объект URL-ны чистартыгыз setTimeout (() => URL.revokeObjectURL (url), 100); }
Бу функция сезнең мәгълүматлардан Блоб (икеләтә зур объект) ясап, аның өчен вакытлыча URL ясап, программалы рәвештә йөкләү сылтамасына басып эшли. Чистарту хәтернең агып чыкмавын тәэмин итә. 2 адым: JSON экспортын эшләгез JSON тулы мәгълүмат структурасын саклау өчен бик яхшы:
// =================================== // JSON кебек экспорт // ===================================
document.getElementById ("экспорт-json"). addEventListener ("басыгыз", () => { // Экспортлау өчен берәр нәрсә барлыгын тикшерегез if (! frames.length) { console.warn ("Экспортка язу юк."); кайту; }
// Мета мәгълүматлар һәм рамкалар белән йөкләү ясагыз const payload = { барлыкка китерелгән: яңа Дата (). toISOString (), рамнар };
// JSON форматланган итеп йөкләү downloadFile ( "gamepad-log.json", JSON.stringify (йөкләү, нуль, 2), "кушымта / json" ); });
JSON форматы барысын да структуралы һәм җиңел итеп анализлый, аны коралларга яңадан йөкләү яки яшьтәшләр белән уртаклашу өчен идеаль итә. 3 адым: CSV экспортын эшләгез CSV экспорты өчен безгә иерархик мәгълүматны рәтләргә һәм баганаларга тигезләргә кирәк:
//=================================== // CSV кебек экспорт // ===================================
document.getElementById ("экспорт-csv"). addEventListener ("басыгыз", () => { // Экспортлау өчен берәр нәрсә барлыгын тикшерегез if (! frames.length) { console.warn ("Экспортка язу юк."); кайту; }
// CSV баш рәтен төзегез (вакыт маркасы өчен баганалар, барлык төймәләр, барлык уклар) const headerButtons = рамкалар [0] .buttons.map ((_, i) => btn $ {i}); const headerAxes = рамкалар [0] .axes.map ((_, i) => күчәр $ {i}); const header = ["t", ... headerButtons, ... headerAxes] .join (",") + "\ n";
// CSV мәгълүмат рәтләрен төзегез const рәтләре = frames.map (f => { const btnVals = f.buttons.map (b => b.value); кайту [f.t, ... btnVals, ... f.axes] .join (","); }). кушылырга ("\ n");
// CSV итеп йөкләү downloadFile ("gamepad-log.csv", баш + рәтләр, "текст / csv"); });
CSV мәгълүмат анализы өчен искиткеч, чөнки ул турыдан-туры Excel яки Google Sheets'та ачыла, схемалар, фильтрлар яки визуаль күренешләр ясарга мөмкинлек бирә. Хәзер экспорт төймәләре булганда, сез панельдә ике яңа вариант күрерсез: Export JSON һәм CSV Export. JSON чималны кире коралларыгызга ташларга яки структураны әйләндерергә теләсәгез яхшы. CSV, киресенчә, Excel яки Google Sheets'ка туры ачыла, сез керемнәрне диаграмма, фильтр яки чагыштыра аласыз. Түбәндәге рәсем панельнең нинди өстәмә контроль белән булуын күрсәтә.
3. Снэпшот системасы Кайвакыт сезгә тулы язу кирәк түгел, кертү халәтләренең тиз "скриншоты" гына. Менә шунда "Snapshot" төймәсе ярдәм итә.
Һәм JavaScript:
// =================================== // СНАПШОТ алыгыз // ===================================
document.getElementById ("скриншот"). addEventListener ("басыгыз", () => { // Барлык тоташтырылган уен уеннарын алыгыз const pads = navigator.getGamepads (); const activePads = [];
// connectedәрбер бәйләнгән уен тактасының торышын әйләндереп алыгыз өчен (const gp pad) { әгәр (! gp) дәвам итсә; // Буш урыннарны атлагыз
activePads.push ({ id: gp.id, // Контроллер исеме / модель вакыт билгесе: performance.now (), төймәләр: gp.buttons.map (b => ({ басылган: б.прессланган, кыйммәт: б })), балталар: [... gp.axes] }); }
// Уен уеннары табылганын тикшерегез if (! activePads.length) { console.warn ("Снэпшот өчен тоташтырылган уеннар юк."); уяу ("Контроллер табылмады!"); кайту; }
// Керегез һәм кулланучыга хәбәр итегез console.log ("Снэпшот:", активПадлар); уяу (Снэпшот алынды! $ {activePads.length} контроллер (лар) алынды.); });
Снэпшотлар контроллерның төгәл халәтен бер мизгелдә туңдыралар. 4. Арбаны кертү репликасы Хәзер күңелле өчен: арбаны кертү репликасы. Бу бүрәнәне ала һәм аны фантастик уйнаучы контроллер кулланган кебек визуаль рәвештә уйный.
Кабатлау өчен JavaScript: // =================================== // ГОСТ ТАПШЫРУ // ===================================
document.getElementById ("кабатлау"). addEventListener ("басыгыз", () => { // Кабатлау өчен язуыбыз барлыгына инаныгыз if (! frames.length) { уяу ("Кабатлау өчен язма юк!"); кайту; }
console.log ("Арбаны кабатлау ...");
// Синхрон уйнау өчен вакытны күзәтегез startTime = performance.now (); frameIndex = 0 булсын;
// Анимация циклын кабатлау функция адымы () { const хәзер = performance.now (); const узган = хәзер - startTime;
// Хәзерге вакытта булырга тиеш булган барлык рамнарны эшкәртү
шул вакытта (frameIndex // Язылган төймә халәтләре белән UI-ны яңарту
btnA.classList.toggle ("актив", frame.buttons [0]. басылган);
btnB.classList.toggle ("актив", frame.buttons [1]. басылган);
btnX.classList.toggle ("актив", frame.buttons [2]. басылган); // Статус күрсәтүне яңарту
басылсын = [];
frame.buttons.forEach ((btn, i) => {
if (btn.pressed) press.push ("төймә" + i);
});
if (press.length> 0) {
status.textContent = "Ghost:" + pressed.join (",");
} frameIndex ++;
} // Рамнар күбрәк булса, циклны дәвам итегез
if (frameIndex // Репетицияне башлау
адым ();
}); Дебутацияне бераз кулайрак итәр өчен, мин арбаны кабатладым. Сессияне яздырып алганнан соң, сез репликага басыгыз һәм UI-ның эшләвен карый аласыз, фантаст плейер такта эшләгән кебек. Моның өчен панельдә яңа Ghost Replay төймәсе күрсәтелә. Рекордка басыгыз, контроллер белән бераз буталыгыз, туктагыз, аннары кабат уйнагыз. UI сезнең эшләгәннәрегезнең барысын да кабатлый, керемнәрегезгә ияргән арбак кебек.
Нигә бу өстәмәләр белән борчылырга? Язу / экспорт сынаучыларга нәрсә булганын төгәл күрсәтүне җиңеләйтә.
Снэпшотлар бер мизгелдә туңалар, сәер хата җибәргәндә супер файдалы.
Ghost репликасы дәреслекләр, мөмкинлекләрне тикшерү, яисә контроль көйләүләрне чагыштыру өчен бик яхшы. Бу вакытта ул чиста демо гына түгел, ә сез чынлап та эшкә урнаштыра алырлык нәрсә.
Реаль дөньяда куллану очраклары
Хәзер без бик күп эшли алырлык бу төзәтүче алдык. Ул тере кертүне күрсәтә, бүрәнәләрне яздыра, аларны экспортлый һәм хәтта әйберләрне кабатлый. Ләкин чын сорау: кем кайгырта? Бу кем өчен файдалы?
Уен уйлап табучылар
Контроллерлар эшнең бер өлеше, ләкин аларны төзәтү? Гадәттә авырту. Күз алдыгызга китерегез, сез ↓ → + пунч кебек сугыш уенын сынап карыйсыз. Дога кылу урынына, сез аны ике тапкыр бер үк бастыгыз, бер тапкыр яздырасыз һәм кабат кабатлыйсыз. Булды. Яисә сез JSON бүрәнәләрен иптәшегез белән алыштырасыз, сезнең мультиплеер кодыгыз аларның машинасында шундый ук реакциядә икәнлеген тикшерү өчен. Бу бик зур.
Практиклар
Бу минем йөрәгемә якын. Барысы да "стандарт" контроллер белән уйнамый. Адаптив контроллерлар кайвакыт сәер сигналлар ташлыйлар. Бу корал ярдәмендә сез нәрсә булганын төгәл күрә аласыз. Укытучылар, тикшерүчеләр, кем дә булса. Алар бүрәнәләрне тотып ала, чагыштыра яки керемнәрне янәшә кабатлый ала. Кинәт күренми торган әйберләр ачыклана.
Сыйфатны тикшерү
Тестчылар гадәттә "Мин монда төймәләрне пешердем, ул өзелде" кебек язмалар яза. Бик файдалы түгел. Хәзер? Алар төгәл прессларны кулга ала, бүрәнәне экспортлый һәм җибәрә ала. Фаразлау юк.
Тәрбиячеләр
Әгәр дә сез дәреслекләр яки YouTube видеолары ясыйсыз икән, арбаны кабатлау алтын. Сез турыдан-туры әйтә аласыз, "Менә мин контроллер белән нәрсә эшләдем", UI моны күрсәтә. Аңлатмаларны тагын да ачыграк ясый.
Уеннар артында
Әйе, бу уеннар турында гына түгел. Кешеләр роботлар, сәнгать проектлары, интерфейс өчен контроллер кулландылар. Timeәрвакыт бер үк проблема: браузер нәрсә күрә? Моның белән сез фаразларга тиеш түгел.
Йомгаклау
Контроллер кертүен төзәтү һәрвакыт сукыр очкан кебек тоелды. DOM яки CSSдан аермалы буларак, уен кораллары өчен урнаштырылган инспектор юк; бу консольдәге чиста саннар, шау-шуда җиңел.
HTML, CSS һәм JavaScriptның берничә йөз сызыгы белән без бүтән нәрсә төзедек: Күренми торган керемнәрне күренеп торган визуаль төзәтүче.
UIны чиста һәм төзәтеп торган катлаулы CSS системасы.
Аны демодан эшкәртүче коралына күтәрә торган өстәмәләр җыелмасы (язу, экспортлау, снэпшотлар, арбаны кабатлау). Бу проект веб-платформаның көчен CSS Каскад катламнарында бераз иҗат белән кушып, никадәр ераклашырга мөмкинлеген күрсәтә.
Мин тулысынча аңлаткан корал ачык чыганак. Сез GitHub репосын клонлаштырып, үзегез сынап карый аласыз.
Ләкин иң мөһиме, сез аны үзегезнеке итә аласыз. Ownз катламнарыгызны өстәгез. Repзегезнең реплика логикасын төзегез. Аны уен прототибы белән берләштерегез. Яисә аны мин күз алдыма китермәгәнчә кулланыгыз. Укыту, мөмкинлек, яки мәгълүмат анализы өчен.
Көн ахырында бу уен уеннарын төзәтү турында гына түгел. Бу яшерен керемнәргә яктырту, һәм уйлап табучыларга веб әле тулысынча кабул итмәгән аппарат белән эшләргә ышаныч бирү турында.
Шулай итеп, контроллерыгызны кабызыгыз, редакторыгызны ачыгыз һәм эксперимент башлыйсыз. Сез браузерыгыз һәм CSS чыннан да нәрсә эшли алуына гаҗәпләнергә мөмкин.