از این کتابخانه برای خواندن فایلهای اکسل هم میتوان استفاده کرد. یک مثال
آشنایی با Oslo - قسمت اول
لطفا شما هم بنویسید. از خواندن مقالات شما لذت میبرم. ;)
// نصب لودرهای مورد نظر npm install css-loader style-loader -D
//index.html file <html> <head> <title>webpack part 4</title> </head> <body> <h1>webpack is awesome</h1> <p>part 4 of tutorial</p> <div>i have a background</div> <h1>تست فونت !</h1> <script src="/assets/js/bundle.js"> </script> </body> </html>
//webpack.config.js var path = require("path"); var webpack = require("webpack"); module.exports = { context: path.resolve("js"), entry: ['./main.js'] , output: { path: path.resolve("build/js"), publicPath: "assets/js", filename: 'bundle.js' }, devServer: { contentBase: "assets" } , watch: true , module: { loaders: [ { test: /\.css$/ , exclude: /node_modules/ , loader: 'style-loader!css-loader' } ] } }
loader:'style-loader!css-loader'
// main.js file require("./../assets/main.css"); console.log(`i'm bundled by webpack`);
// main.css body{ background-color: #DAA520; }
در تصویر بالا مشخص است که در تگ Head صفحه، یک تگ جدید style، توسط وبپک ایجاد شده و استایل ما به صفحه تزریق شدهاست. همچنین اگر وبپک را به حالت Minify کردن باندل ببریم (در مطلب قبلی نحوهی این کار ذکر شد)، باندل نهایی برای فایلهای css نیز Minify خواهد شد.
استفاده از Sass با کمک وبپک
روش استفاده از Sass نیز تفاوتی با css نخواهد داشت و فقط کافی است Loader آن را در پروژه نصب کنیم و در نهایت آن را در فایل پیکربندی، به وبپک معرفی کنیم. با دستور زیر لودر Sass را در پروژه وارد میکنیم:
// نصب لودر sass npm install -D sass-loader node-sass
( node-sass به عنوان وابستگی لودر sass، در کنار آن نصب شده است)
حال به فایل پیکربندی میرویم و لودر جدید را به قسمت لودرها اضافه میکنیم:
// webpack.config.js module: { loaders: [ { test: /\.css$/ , exclude: /node_modules/ , loader: 'style-loader!css-loader' } ,{ test:/\.scss$/ ,exclude:/node_modules/ ,loader:'style-loader!css-loader!sass-loader' } ] }
در پوشهی assets نیز فایل جدیدی را با عنوان main.scss ساخته و محتوای زیر را در آن وارد میکنیم:
// main.scss $background-color:#DAA520; body{ background-color: $background-color; }
سپس در فایل main.js به جای وارد کردن فایل css قبلی، فایل scss جدید را با کمک require وارد میکنیم و در ادامه وبپک را اجرا میکنیم. خواهیم دید که مانند قبل بدون مشکلی وبپک اجرا شده، فایل scss را به css ترجمه کرده و سپس به کمک بقیه لودرها، به باندل اضافه میکند. استفاده از بقیهی فریمورکهای css مانند Less و ... نیز با کمک لودر آنها به همین صورت قابل انجام است.
استفاده از Autoprefixer
همان طور که تمامی قابلیتهای نسخهی جدید جاوااسکریپت در همهی مرورگرها به صورت سراسری پشتیبانی نمیشود، برای css نیز چنین مشکل مشابهی وجود دارد و برای استفادهی بهینهی از برخی قابلیتها نیاز داریم تا prefixهای مورد نیاز مرورگرهای مختلف را به فایلهای css مان اضافه کنیم. میتوانیم این روند را با کمک یک لودر وبپک، ساده و به صورت خودکار کرد. برای نصب این لودر دستور زیر را وارد میکنیم:
npm install -D autoprefixer-loader
و بعد از نصب شدن آن، در فایل پیکربندی وبپک به لودرهایی که برای فایلهای css و scss اضافه کرده بودیم، این لودر را نیز به صورت زنجیر وار اضافه میکنیم:
//webpack.config.js module: { loaders: [ { test: /\.css$/ , exclude: /node_modules/ , loader: 'style-loader!css-loader!autoprefixer-loader' } ,{ test:/\.scss$/ ,exclude:/node_modules/ ,loader:'style-loader!css-loader!autoprefixer-loader!sass-loader' } ] }
در هر دو لودری که برای css و scss ساخته بودیم، از لودر autoprefixer استفاده کردیم. برای تست اینکه این لودر بدون مشکل کار میکند، در فایل main.scss تغییر زیر را ایجاد میکنیم:
//main.scss $background-color:#DAA520; body{ background-color: $background-color; display: flex; }
حال با اجرای وبپک خواهیم دید که prefixهای مورد نیاز توسط لودر اضافه شده اند ( این لودر از کتابخانهی postcss کمک میگیرد).
باندل کردن تصاویر و فونتها با کمک وبپک
تا اینجا با نحوهی وارد کردن فایلهای استایل، مانند css و ... به باندل آشنا شدیم. در ادامه قصد داریم که تصاویر و فونتها را نیز وارد باندل کنیم. روند کار شبیه به گذشته است و این کار نیز به کمک لودرهای وبپک انجام خواهد شد.
جهت باندل کردن تصاویر و فونتها، به لودر جدیدی با نام url-loader احتیاج داریم. قبل از هر چیزی این لودر را در پروژه با کمک npm نصب میکنیم:
npm install -D url-loader file-loader
(لودر file-loader به عنوان وابستگی مورد نیاز است)
روند همچنان مثل گذشته است و پس از نصب لودر، وارد فایل پیکربندی شده و لودر جدید را به وبپک معرفی میکنیم:
//webpack.config.js file module: { loaders: [ { test: /\.css$/ , exclude: /node_modules/ , loader: 'style-loader!css-loader!autoprefixer-loader' } ,{ test:/\.scss$/ ,exclude:/node_modules/ ,loader:'style-loader!css-loader!autoprefixer-loader!sass-loader' },{ test:/\.(png|jpg|ttf|eot)$/ ,exclude:/node_modules/ ,loader:'url-loader?limit=100000' } ] }
در لودر اضافه شده، پسوند فایلهایی را که قصد داریم به باندل وارد شوند، معرفی میکنیم. در اینجا فرمتهای png , jpg ,ttf, eot ذکر شدهاند.
تنها نکتهی جدید، در مشخص کردن نام لودر وجود دارد و آن نیز قسمت پس از علامت ؟ میباشد. هنگام مشخص کردن اینکه از چه لودری قصد استفاده داریم، میتوانیم با استفاده از ؟ پارامترهایی را به لودر مورد نظر ارسال کنیم. در اینجا به پارامتر limit، مقدار 100000 را دادهایم که برای این لودر به این معناست که اگر حجم فایل در حال پردازش، حجمی بیشتر از این مقدار را داشت، این فایل را به صورت یک لینک جدا از باندل قرار بده. ولی اگر حجمی کمتر از این مقدار داشت، لودر به صورت خودکار فایل را به فرمت Base64 انکود میکند و در درون باندل قرار میدهد.
برای تست اینکه آیا این لودر به درستی کار میکند یا نه، یک تصویر نمونه را در فولدر assets قرار میدهیم و سپس در فایل main.scss تغییرات زیر را انجام میدهیم.
حجم عکس قرار داده شده نزدیک به 400 کیلوبایت است و با مقدار محدودیت مشخص شده، تصویر مورد نظر از باندل توسط وبپک خارج میشود و به صورت جداگانه در بیلد نهایی قرار میگیرد. در تصویر زیر مشخص است که مرورگر درخواست جداگانه ای برای تصویر ارسال کرده است:
حال محدودیت حجم فایل را بالا میبریم و میتوان دید که تصویر در باندل نهایی به صورت انکود شده قرار گرفته است .
قطعا انجام این کار برای تصاویری با حجم بالا مناسب نخواهد بود و برنامه نویس بسته به نیاز بایستی مقدار محدودیت حجم را برای لودر مشخص کند.
در تعریف بالا دیدیم که فرمتهای مورد نیاز برای وارد کردن فونت را نیز علاوه بر تصاویر، برای وبپک مشخص کردهایم. روند وارد کردن فونتها به باندل نیز تفاوتی با تصاویر ندارد و کافی است تعاریف مورد نیاز را در فایلهای css داشته باشیم.
برای مثال فونت ساحل در پوشهی assets قرار داده شده و در فایل main.scss تغییرات زیر انجام شدهاند:
// main.scss $background-color:#DAA520; div{ background-image: url("galaxy.jpg"); } @font-face { font-family: Sahel; src: url('Sahel.eot'); src: url('Sahel.eot?#iefix') format('embedded-opentype'), url('Sahel.woff') format('woff'), url('Sahel.ttf') format('truetype'); font-weight: normal; } @font-face { font-family: Sahel; src: url('Sahel-Bold.eot'); src: url('Sahel-Bold.eot?#iefix') format('embedded-opentype'), url('Sahel-Bold.woff') format('woff'), url('Sahel-Bold.ttf') format('truetype'); font-weight: bold; } @font-face { font-family: Sahel; src: url('Sahel-Black.eot'); src: url('Sahel-Black.eot?#iefix') format('embedded-opentype'), url('Sahel-Black.woff') format('woff'); font-weight: 900; } body{ background-color: $background-color; font-family: 'Sahel'; display: flex; }
تصویر زیر، نتیجهی اجرای وبپک برای تولید باندل است. در تصویر میتوان دید که هم فونتها و هم فایلهای تصاویر، توسط وبپک شناسایی شده و وارد باندل شدهاند:
روش دیگری برای وارد کردن تصاویر نیز موجود است؛ به این صورت که به فرض مثال یک تگ img در اسکریپت ساخته و سپس پروپرتی src آن را با کمک require برابر با آدرس تصویر مورد نظر قرار میدهیم. این روش نیز برای وبپک قابل فهم بوده و فایل وارد باندل میشود. در ادامه مثالی از این روش آورده شده است:
var img = document.createElement("img"); img.width="200px"; img.height="200px"; img.src= require("path to some image");
چند نکتهی پایانی :
1. در فایل پیکربندی همیشه پسوند فایلهایی را که در کلید entry قرار داشتند، مشخص کردیم:
entry:['./main.js','./shared.ts']
با کلیدی با نام resolve در فایل پیکربندی میتوان مشخص کرد در صورتیکه پسوند فایلی مشخص نبود، به ترتیب مشخص شده به دنبال آن بگردد. به طور مثال:
// webpack.config.js resolve:{ extensions:['','.js','.ts'] }
در تعریف بالا ذکر میشود در صورتیکه پسوند فایل ورودی مشخص نبود، ابتدا به دنبال فایل بدون پسوند، سپس فایلهایی با پسوند js و در نهایت به دنبال فایلهایی با پسوند ts بگرد. توجه داشته باشید که ترتیب مشخص کردن پسوند فایلها مهم است و وبپک بر اساس این ترتیب به دنبال فایل مورد نظر خواهد گشت.
حال میتوان مقدار کلید entry را اینطور تعریف کرد:
entry:['./main','./shared']
2.استفاده از فایلهای css ی که در درونشان فونتهای مورد نیاز لینک شدهاند تنها با استفاده از لودر css قابل انجام نیست. به طور مثال استفاده از کتابخانهی بوت استرپ تنها با این لودر ممکن نیست و بایستی لودر url-loader نیز در پروژه نصب شده باشد تا در هنگامیکه وبپک به فونتها برخورد کرد، بتواند آنها را وابسته به شرایط، وارد باندل نهایی کند.
فایلهای پروژه: dntwebpack-part4.zip
@using (Ajax.BeginForm(actionName: "Index", controllerName: "Home", ajaxOptions: new AjaxOptions { HttpMethod = "POST", OnSuccess = "doUpload(data, status, xhr)" }, routeValues: null, htmlAttributes: new { id = "uploadForm" })) {
function doUpload(data, status, xhr) { alert(data.result); // مابقی کدهای آپلود فایل
جهت تکمیل بحث
• OnBegin – xhr • OnComplete – xhr, status • OnSuccess – data, status, xhr • OnFailure – xhr, status, error
using (var store = new DocumentStore { Url = "http://localhost:8080" }.Initialize()) { using (var session = store.OpenSession()) { store.DatabaseCommands.PutAttachment(key: "file/1", etag: null, data: System.IO.File.OpenRead(@"D:\Prog\packages.config"), metadata: new RavenJObject { { "Description", "توضیحات فایل" } }); var question = new Question { By = "users/Vahid", Title = "Raven Intro", Content = "Test....", FileId = "file/1" }; session.Store(question); session.SaveChanges(); } }
RavenFS یک فایل سیستم مجازی توزیع شدهاست و برای فایلهای بزرگ چند گیگابایتی به طور بهینهای طراحی گردیدهاست تا کارآیی بانک اطلاعاتی را بالا ببرد و وجود فایلهای تکراری، از بین برود. این سیستم جدید شامل سیستم پیش فرض ایندکس گذاری میباشد و به شما این اجازه را میدهد تا بر روی متادیتاهای یک فایل از قبیل حجم، تاریخ آخرین نگارش و حتی متادیتاهای اختصاصی که شما در حین ذخیره سازی به آن اضافه میکنید، به جستوجو بپردازد. این سیستم جدید همچنین این امکان را به شما میدهد تا این اطلاعات را بین Nodeها، با کمترین میزان انتقالات جابجا کنید و دسترسی سریعتری را بین نودهای مختلف داشته باشید.
برای ذخیره سازی یک فایل ابتدا باید یک FileStore را همانند آنچه که برای DocumentStore داشتید تعریف کنید. Url که شامل همان رشته اتصالی بوده و DefaultFileSystem هم همانند DefaultDatabase که نام دیتابیس در آن ذکر میشد، در اینجا نام فایل سیستم ذکر میگردد:
var fileStore = new FilesStore() { Url = "http://localhost:8080", DefaultFileSystem = "SampleFs" }; fileStore.Initialize();
بعد از آن باید از طریق Store جدید یک سشن ایجاد شود و فایل مورد نظر را در قالب یک استریم بخوانیم:
var session = fileStore.OpenAsyncSession(); var stream = File.OpenRead("D:\\Apocalypse.Now.Redux.1979.BDRip.YIFY.mkv");
توجه داشته باشید که برای کار با فایل سیستم، همه متدهای session به صورت غیرهمزمان بوده و متد همزمانی وجود ندارد. سپس در مرحله بعد میخواهم متادیتاهای شخصی نیز به آن اضافه کنیم:
var metadata = new RavenJObject { {"User", "users/1345"}, {"Director","Francis Ford Coppola" }, {"Year","1979" } };
با استفاده از شیء RavenObject میتوانیم در قالب کلید و مقدار، مقادیر خود را ذخیره کنیم و بعد از آن همه موارد بالا که شامل فایل هدر، استریم و متادیتای اختصاصی است را رجیستر کنیم. اگر هم چندین فایل داریم میتوانید آنها را هم در همینجا رجیستر کنید:
session.RegisterUpload("mkv/sample.mkv", stream, metadata);
در مرحله بعدی تغییرات را تایید و عملیات آپلود آغاز میگردد:
await session.SaveChangesAsync();
همانطور که میبینید تمامی متدهای کاربردی این سشن به طور غیرهمزمان طراحی شدهاند.
کلیه عملیاتی که در بالا انجام شد:
var fileStore = new FilesStore() { Url = "http://localhost:8080", DefaultFileSystem = "SampleFs" }; fileStore.Initialize(); var session = fileStore.OpenAsyncSession(); var stream = File.OpenRead("D:\\Apocalypse.Now.Redux.1979.BDRip.YIFY.mkv"); var metadata = new RavenJObject { {"User", "users/1345"}, {"Director","Francis Ford Coppola" }, {"Year","1979" } }; session.RegisterUpload("Mkv/sample.mkv", stream, metadata); await session.SaveChangesAsync();
حالا اگر به نسخه سرور ravenDb مراجعه کنید میبینید که فایل طبق فایل هدر داده شده قرار گرفته است و اطلاعات مربوط به آن ذخیره شده است:
{ "User": "users/1345", "Country": "Iran", "City": "Kashan", "Raven-Synchronization-History": [ { "Version": 4, "ServerId": "42d0cccb-103d-4bf0-9f3d-6f635b1c8ba4" }, { "Version": 5, "ServerId": "42d0cccb-103d-4bf0-9f3d-6f635b1c8ba4" } ], "Raven-Synchronization-Version": "6", "Raven-Synchronization-Source": "42d0cccb-103d-4bf0-9f3d-6f635b1c8ba4" }
برای خواندن هم به شیوه زیر عمل میکنیم:
از طریق Store ایجاد شده، یک سشن جدید را باز میکنیم و فایل مورد نظر را از طریق یکی از متادیتاهای تعریف شده بازیابی میکنیم:
var fileStore = new FilesStore() { Url = "http://localhost:8080", DefaultFileSystem = "SampleFs" }; fileStore.Initialize(); var session = fileStore.OpenAsyncSession(); var file = await session.Query() .WhereEquals("Year", "1979") .FirstOrDefaultAsync();
var stream = await session.DownloadAsync("mkv/"+file.Name);
سپس استریم را روی دیسک سخت دخیره یا به هر مکانی که مد نظر است ارسال میکنیم:
var fs = File.Create("D:\\file2.mkv"); stream.CopyTo(fs); fs.Flush(); fs.Close();
await stream.CopyToAsync(fs);
سپس کل کد بازیابی را به شکل زیر مینویسیم:
var fileStore = new FilesStore() { Url = "http://localhost:8080", DefaultFileSystem = "SampleFs" }; fileStore.Initialize(); var session = fileStore.OpenAsyncSession(); var file = await session.Query() .WhereEquals("Year", "1979") .FirstOrDefaultAsync(); var stream = await session.DownloadAsync("mkv/"+file.Name); var fs = File.Create("D:\\file2.mkv"); await stream.CopyToAsync(fs);
<input type="text" ng-model="newItemTitle"> <button type="button" ng-click="add()">افزودن</button> <ul> <li ng-repeat="item in items">{{item.title}}</li> </ul> <div ng-show="showMSG()">شما بیش از ۱۰ استان ثبت کرده اید</div>
$scope.newItemTitle=''; $scope.add=function(){ $scope.items.push({ title:$scope.newItemTitle }); } $scope.items=[ {title:'اردبیل'}, {title:'تهران'}, {title:'اصفهان'}, {title:'شیراز'}, {title:'مشهد'}, ]; $scope.showMSG=function(){ return $scope.items.length>10; }
ng-show="showMSG()" ng-if="showMSG()" ng-hide="showMSG()==false" ng-class="{'red',getResult()}" ng-style="{'width':getWidth()}"
<div ng-show="items.length>10">شما بیش از ۱۰ استان ثبت کرده اید</div>
$scope.maxItem=false'; $scope.add=function(){ $scope.items.push({ title:$scope.newItemTitle }); $scope.maxItem=$scope.items.length>10; }
<div ng-show="maxItem">شما بیش از ۱۰ استان ثبت کرده اید</div>
Sqlite دیتابیس مناسبی برای برنامههای چندسکویی است و عموما به عنوان اولین گزینه استفاده میشود. برای کار با این دیتابیس، ما از ماژول sql.js که یکی از ماژولهای معروف در جاوااسکریپت است، استفاده میکنیم. برای نصب آن از طریق npm، به شکل زیر اقدام میکنیم:
npm install sql.js --save
const{app,BrowserWindow}=require("electron"); let win; function onLoad() { win=new BrowserWindow({ width:800, height:600 }); win.loadURL(`file://${__dirname}/index.html`); } app.on("ready",onLoad());
var path=require("path"); path.exists('filepath",(status)=> { .... }); var status=path.existsSync("file"); //=============================== var fs=require("fs"); fs.exists('filepath",(status)=> { .... }); var status=path.existsSync("file");
fs.stat('foo.txt', function(err, stat) { if(err == null) { console.log('فایل موجوده'); } else if(err.code == 'ENOENT') { // فایل وجود نداره fs.writeFile('log.txt', 'Some log\n'); } else { //خطای دیگری رخ داده است } });
try { stats = fs.statSync(path); console.log("File exists."); } catch (e) { console.log("File does not exist."); }
const fs = require('fs'); const sql = require('sql.js'); dbPath = './mydb.sqlite'; dbExists=false; try { dbExists = fs.statSync(dbPath); } catch (e) { } if(!dbExists) { //create Database var sqlStr=fs.readFileSync("./sql.txt"); var db = new sql.Database(); db.run(String(sqlStr)); //write to disk var data=db.export(); var buffer=new Buffer(data); fs.writeFileSync(dbPath,buffer); } else{ var buffer = fs.readFileSync(dbPath); var db = new sql.Database(buffer); }
CREATE TABLE numbers ( id INT PRIMARY KEY UNIQUE NOT NULL, fname VARCHAR (20) NOT NULL, lname VARCHAR (30) NOT NULL, number VARCHAR (15) NOT NULL ); insert into numbers values(1,'ali','yeganeh','03111223344'); insert into numbers values(2,'xxx','yyy','45454555');
بعد از آن نیاز است تا دیتابیس در دسترس Render Processها قرار بگیرد که در مقاله "شیوه کدنویسی در الکترون " در مورد global صحبت کردهایم و نحوه استفاده از آن را فرا گرفتیم:
global.db=db;
در پایان اجرای برنامه لازم است که دیتابیس توسط دستور close بسته شود. سپس کد زیر را در رویداد windows-all-closed مینویسیم:
app.on('window-all-closed', () => { db.close(); if (process.platform !== 'darwin') { app.quit(); } });
(چند مورد خارج از بحث): کد بعدی که مورد استفاده قرار گرفته است و در مقالات قبلی در مورد آن صحبت نکردهایم این است که در سیستمهای مک، وضعیت به این قرار است که اگر شما برنامه را ببیندید، آن برنامه بسته نشده و در پس زمینه فعال است و میتوانید آن را از طریق dock اطراف صفحه، مجددا فعال کنید. ولی با نوشتن کد بالا، ما این وضعیت را اعلام کردهایم که اگر تمامی پنجرهها بسته شدند، کل برنامه را ببند.
همچنین بسیار خوب است که کد زیر را هم همیشه اضافه کنید:
win.on('closed', () => { win = null; });
پس اگر این کد را نوشتید، وضعیت سیستم عامل مک را به خاطر داشته باشید و مجبور هستید کد زیر را نیز اضافه کنید:
app.on('activate', () => { if (win === null) { createWindow(); } });
بعد از اینکه دیتابیس را به شیء global دادیم، در صفحه html کد زیر را وارد میکنیم:
<html> <head> <script src="./jquery.min.js"></script> <link href="./bootstrap-3.3.6-dist/css/bootstrap.min.css" rel="stylesheet"></link> <meta charset="utf-8"> <title></title> <script> const {remote}=require("electron"); let db=remote.getGlobal("db"); </script> </head> <body> <table id="people" class="table table-hover table-striped"> <th> <tr> <td>First Name</td> <td>last Name</td> <td>Phone Number</td> </tr> </th> <tbody> </tbody> </table> </body> </html>
$(document).ready(()=> { //show data var tableBody=$("#people"); db.each("select * from numbers",(row)=>{ let rowTemplate=`<tr><td>${row.fname}</td><td>${row.lname}</td><td>${row.number}</td></tr>`; tableBody.append(rowTemplate); });
حال وقت آن رسیده است که خروجی کار را ببینیم. پس کد npm start را اجرا میکنیم. همانطور که میبینید خروجی به راحتی نمایش داده میشود. در مقاله بعدی بیشتر در این مورد صحبت میکنیم.
وبلاگها و سایتهای ایرانی
امنیت
Visual Studio
ASP. Net
طراحی وب
PHP
- Aptana PHP 1.0 منتشر شد (اگر قبلا این IDE بسیار قابل توجه را دریافت کرده بودید فقط کافی است به منوی aptana و گزینه my aptana مراجعه کرده و از قسمت plugins ، این پلاگین 18 مگابایتی را دریافت کنید.)
اسکیوال سرور
سی شارپ
عمومی دات نت
ویندوز
متفرقه
- مزایای مهاجرت از ویژوال سورس سیف مایکرسافت به SVN
- افزونهای برای فایرفاکس جهت GUI prototyping (خیلی کار جالبی کرده ولی چرا به صورت یک افزونه؟)
PM> Install-Package Twitter.Bootstrap.Less
.loud { color: red; } // Make all H1 elements loud h1 { .loud; }
<div class="container"> <div class="row"> <div class="col-md-8"> Content - Main </div> <div class="col-md-4"> Content - Secondary </div> </div> </div>
<div class="wrapper"> <div class="content-main"> Content - Main </div> <div class="content-secondary"> Content - Secondary </div> </div>
// Core variables and mixins @import "variables.less"; @import "mixins.less"; .wrapper { .make-row(); } .content-main { .make-lg-column(8); } .content-secondary { .make-lg-column(3); .make-lg-column-offset(1); }
.wrapper { margin-left: -15px; margin-right: -15px; } .content-main { position: relative; min-height: 1px; padding-left: 15px; padding-right: 15px; } @media (min-width: 1200px) { .content-main { float: left; width: 66.66666666666666%; } } .content-secondary { position: relative; min-height: 1px; padding-left: 15px; padding-right: 15px; } @media (min-width: 1200px) { .content-secondary { float: left; width: 25%; } } @media (min-width: 1200px) { .content-secondary { margin-left: 8.333333333333332%; } }
<!-- Before --> <a href="#" class="btn danger large">Click me!</a> <!-- After --> <a href="#" class="annoying">Click me!</a> a.annoying { .btn; .btn-danger; .btn-large; }