让天下没有难学的编程 |

全部资讯


Introduction to CSS

Introduction Welcome, I'm assuming you're here because you want to get started using CSS. Great Choice! Assuming you have already read my article on getting starting with HTML, than lets get started. If not here is a link to it, you might want to read that before continuing. Lets start. Basics How might do I even link a CSS file to my HTML file? Its very simple, assuming you name the .css file "style" here is an example: <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css"> </head> </html> How do I format CSS? CSS can be a little intimidating to a beginning developer but with some practice it will get easier. Here's an example of a simple div format in a .css file: .div { } As you can see CSS uses braces {} unlike HTML where you would use carrots <>. Everything between the carrots and braces will be included in the element. To take it a step further, we are going to discuss the difference between id and class selectors. <!DOCTYPE html> <html> <div id="example"></div> <div class="example2"></div> </html> #example { } .example2 { } Above you can see the difference when using a id and class selectors. When importing a id selector into a .css file use a # before the name of the element. When importing a class selector into a .css file use a . before the name of the element. Now, you may be wondering what the difference between id and class are, well the difference between an id and a class is that an id can be used to identify one element, whereas a class can be used to identify more than one. Inheritance When it comes to CSS there are a few things you need to know in order to actually make quality content. Inheritance is very important when it comes to complex shapes and elements of a webpage. Inheritance is exactly what it sounds like, an element will inherit a trait from it's parent element. Here is an example grabbed from: (https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance) <!DOCTYPE html> <html> <body> <p class="better">This is a paragraph.</p> <p class="better" id="winning">One selector to rule them all!</p> </body> </html> #winning { background-color: red; border: 1px solid black; } .better { background-color: gray; border: none !important; } p { background-color: blue; color: white; padding: 5px; } Fonts So what's so important about fonts? Well, fonts give the website character, if you visited a website with the default text you would not be turned on and probably would not want to return to the site because of the asthetic of the webpage. Fonts make the page POP. Here is how you can use fun fonts on your website. A great website to use to get fonts fast and free is: https://fonts.google.com simply click the font you want from the list given, this is what you will see: Copy the first box and paste it into the head of your HTML document. After, copy and paste the second box into your id or class that you used for your paragraph. <!DOCTYPE html> <html> <head> <link href="https://fonts.googleapis.com/css?family=Pacifico" rel="stylesheet"> </head> <p class="main"></p> </html> .main { font-family: 'Pacifico', cursive; } Congratulations, you've implemented your font! Shapes Shapes are essential when it comes to learning CSS. In order to truly design a website you need to understand the fundamentals of what shapes consist of. In the example below I will show you a square made using pure CSS. I will explain what everything means in due time. As you can see, if you tried to read the CSS than you could see that you can adjust the height and width of the shape as well as the color. Simple. Now, where it says position: relative this is how you can position a shape on the page. It can either be relative or absolute to the page. Where it says top, bottom, left, right this is how far from the sides the shape is. So if you wanted to move the shape left 200px than you would say: position: relative; right: 200px; As you can see I used the opposite side, in this case, right to move the shape left. Closing Remarks Now hopefully I have enlightened you in the art of CSS and you will go on with your journey and explore the endless opportunities that it offers. To leave you with something influential and inspiring here is a Pen to show how CSS can make anything beautiful! Enjoy! 收起
显示全部文字 查看全文
作者/Conner
时间/2018-04-18 16:33:50

Protecting WebView with Safe Browsing

Since 2007, Google Safe Browsing has been protecting users across the web from phishing and malware attacks. It protects over three billion devices from an increasing number of threats, now also including unwanted software across desktop and mobile platforms. Today, we’re announcing that Google Play Protect is bringing Safe Browsing to WebView by default, starting in April 2018 with the release of WebView 66.Developers of Android apps using WebView no longer have to make any changes to benefit from this protection. Safe Browsing in WebView has been available since Android 8.0 (API level 26), using the same underlying technology as Chrome on Android. When Safe Browsing is triggered, the app will present a warning and receive a network error. Apps built for API level 27 and above can customize this behavior with new APIs for Safe Browsing.An example of a warning shown when Safe Browsing detects a dangerous site. The style and content of the warning will vary depending on the size of the WebView.You can learn more about customizing and controlling Safe Browsing in the Android API documentation, and you can test your application today by visiting the Safe Browsing test URL (chrome://safe-browsing/match?type=malware) while using the current WebView beta.Posted by Nate Fischer, Software Engineer收起
显示全部文字 查看全文
作者/Chrome Blog
时间/2018-04-18 00:00:08

A Common Principle of Boolean Algebra as Stated in George Boole's 'Mathematical Analysis of Logic':

A Common Principle of Boolean Algebra: xy = y Figure 1:  I am, at present reading Boole's Mathematical Analysis of Logic. Statement of the Common Principle: Should: x = U or, in other words: x = 1 Then, in Boolean Notation : xy = y Or, in formal-logic notation: x ∧ y = y . e.g. 1: Let: x = 1 . Let: y = 0 . Hence: xy = y Or, in formal-logic notation: x ∧ y = y , because: 1 × 0 = 0 , or: 1(0) = 0 , or, in formal-logic notation: 1 ∧ 0 = 0 . e.g. 2: Let: x = 1 . Let: y = 1 . Hence: xy = y Or, in formal-logic notation: x ∧ y = y , because: 1 × 1 = 1 , or: 1(1) = 1 , or, in formal-logic notation: 1 ∧ 1 = 1 . Addendum: You may read George Boole's Mathematical Analysis of Logic, for free at Project Gutenberg收起
显示全部文字 查看全文
作者/Ciaran Mc Ardle
时间/2018-04-16 21:14:54

Quick tip for node modules

When writing my node modules, I've come to really quite enjoy using Jest for testing (I've written about how I used tap and it's quite similar). Sometimes however, being able to execute the module on the command line and passing some arbitrary data can be pretty handy, and I've used the following technique on a growing handful of modules I've written.收起
显示全部文字 查看全文
作者/
时间/2018-04-12 19:43:50

10 Amazing CodePen Demos for April 2018

A collection of interesting CodePen demos that you should check out.
查看全文
作者/Georgi Georgiev
时间/2018-04-12 17:56:55

NADCAST.13 с Радо Станков

Фаталният епизод 13 на NADCAST е с моя добре познат събеседник Радо Станков. Основна тема на нашия разговор беше новата версия на React и предстоящите React.NotAConf (http://react-not-a-conf.com/) и Bulgaria Web Summit (https://bulgariawebsummit.com/) конференции. 收起
显示全部文字 查看全文
作者/
时间/2018-04-11 05:00:00

Making of "Logo Synth"

The Story When the redesign of the Drexler site began in late 2016 the goal was to create a system that could be evolved through temporary concepts. As soon as the dust settled we began both building upon and simplifying the previous iteration. Once the adjustments were in place for this recent update we found that the front page needed closure. A suggestion to include a message below the work feed lead to the last-minute idea of featuring an interactive piece at the very end. Recalling chats about having a "trademark sound" on the site, it felt appropriate to give it a playful treatment with an audio component. The Setup 1. Tone.js First an instance of a Tone.js instrument is created. var instrument = new Tone.Synth(); var synthJSON = { "oscillator": { "type": "fatcustom", "partials" : [0.2, 1, 0.3, 0.5, .1], "spread" : 30, "count" : 3 }, "envelope": { "attack": 0.001, "decay": 1.6, "sustain": 0, "release": 1.6 } }; instrument.set(synthJSON); var effect1, effect2; var effect1 = new Tone.Distortion(); effect1JSON = { "distortion" : 0.8, "wet": 0.4 }; effect1.set(effect1JSON); var effect2 = new Tone.PingPongDelay(); effect2JSON = { "delayTime" : "8n", "feedback" : 0.2, "wet": 0.5 }; effect2.set(effect2JSON); instrument.connect(effect1); effect1.connect(effect2); effect2.connect(Tone.Master); function deep_dispose() { if(effect1 != undefined && effect1 != null) { effect1.dispose(); effect1 = null; } if(effect2 != undefined && effect2 != null) { effect2.dispose(); effect2 = null; } if(effect3 != undefined && effect3 != null) { effect3.dispose(); effect3 = null; } if(instrument != undefined && instrument != null) { instrument.dispose(); instrument = null; } } instrument.connect(Tone.Master); instrument.set('volume', -10); note: this tool helped generate the synth settings 2. Interactivity In this case we are working with an SVG that has a fixed number of shapes that are set to trigger different notes and colors when hovered as defined here. var colors = ['#f9ed32','#43f3b7','#f29bc1','#ce9f59','#f29bc1','#ce9f59','#f9ed32','#43f3b7']; var notes = ['A3', 'D3', 'C#3', 'D4', 'A3', 'E3', 'A4', 'C#4']; The bounds of each shape gets compared with the cursor/touch coordinates to turn the element into a strumable synthesizer rendered completely in the browser. $(document).on('mousemove touchstart touchmove', function(e) { if(e.type=='mousemove'){ x = e.pageX; y = e.pageY; } else{ x = e.originalEvent.touches[0].pageX; y = e.originalEvent.touches[0].pageY; } note.each(function(){ $this = $(this)[0]; l = $this.getBoundingClientRect().left; t = $this.getBoundingClientRect().top; w = $this.getBoundingClientRect().width; h = $this.getBoundingClientRect().height; if(x >= l && x <= (l + w) && y >= t && y <= (t + h)){ trigger($(this)[0]); } }) }); note: getBoundingClientRect is needed for SVG elements The following function fires when the cursor/touch position intersect with a shape's bounds with the note and color determined by the position of the element. function trigger(key){ $key = $(key); n = $key.index(); instrument.triggerAttackRelease(notes[n], .6); body.css('background',colors[n]); $key.addClass('trigger'); setTimeout(function(){$(key).removeClass('trigger');},400); } The Result A fun easter egg for our visitors to happen upon for a real-time, nostalgic audio/visual experience. See it in action by going to drxlr.com and scrolling to the bottom of the front page. The Takeaway The full potential of Tone.js is far beyond this demo. Some additional logic was needed to account for browsers without Web Audio API support, but performance/sound is impressively consistent.收起
显示全部文字 查看全文
作者/Daniel Givens
时间/2018-04-06 10:07:42

My take on Redux architecture

Redux is a library that acts as a state container and helps managing your application data flow. It was introduced back in 2015 at ReactEurope conference (video) by Dan Abramov. It is similar to Flux architecture and has a lot in common with it. In this section we will create a small counter app using Redux alongside React. Redux architecture and its main characteristics Similarly to Flux architecture we have the view components (React) dispatching an action. Same action may be dispatched by another part of our system. Like a bootstrap logic for example. This action is dispatched not to a central hub but directly to the store. We are saying &ldquo;store&rdquo; not &ldquo;stores&rdquo; because there is only one in Redux. That is one of the big differences between Flux and Redux. The logic that decided how our data changes lives in pure functions called reducers. Once the store receives an action it asks the reducers about the new version of the state by sending the current state and the given action. Then in immutable fashion the reducer needs to return the new state. The store continues from there and updates its internal state. As a final step, the wired to the store React component gets re-rendered. The concept is pretty linear and again follows the one-direction data flow. Let&rsquo;s talk about all these pieces and introduce a couple of new terms that support the work of the Redux pattern. Actions The typical action in Redux (same as Flux) is just an object with a type property. Everything else in that object is considered a context specific data and it is not related to the pattern but to your application logic. For example: const CHANGE_VISIBILITY = \'CHANGE_VISIBILITY\'; const action = { type: CHANGE_VISIBILITY, visible: false } It is a good practice that we create constants like CHANGE_VISIBILITY for our action types. It happens that there are lots of tools/libraries that support Redux and solve different problems which do require the type of the action only. So it is just a convenient way to transfer this information. The visible property is the meta data that we mentioned above. It has nothing to do with Redux. It means something in the context of the application. Every time when we want to dispatch a method we have to use such objects. However, it becomes too noisy to write them over and over again. That is why there is the concept of action creators. An action creator is a function that returns an object and may or may not accept an argument which directly relates to the action properties. For example the action creator for the above action looks like this: const changeVisibility = visible =&gt; ({ type: CHANGE_VISIBILITY, visible }); changeVisibility(false); // { type: CHANGE_VISIBILITY, visible: false } Notice that we pass the value of the visible as an argument and we don&rsquo;t have to remember (or import) the exact type of the action. Using such helpers makes the code compact and easy to read. Store Redux provides a helper createStore for creating a store. Its signature is as follows: import { createStore } from \'redux\'; createStore([reducer], [initial state], [enhancer]); We already mentioned that the reducer is a function that accepts the current state and action and returns the new state. More about that in a bit. The second argument is the initial state of the store. This comes as a handy instrument to initialize our application with data that we already have. This feature is the essence of processes like server-side rendering or persistent experience. The third parameter, enhancer, provides an API for extending Redux with third party middlewares and basically plug some functionally which is not baked-in. Like for example an instrument for handling async processes. Once created the store has four methods - getState, dispatch, subscribe and replaceReducer. Probably the most important one is dispatch: store.dispatch(changeVisibility(false)); That is the place where we use our action creators. We pass the result of them or in other words action objects to this dispatch method. It then gets spread to the reducers in our application. In the typical React application we usually don&rsquo;t use getState and subscribe directly because there is a helper (we will see it in the next sections) that wires our components with the store and effectively subscribes for changes. As part of this subscription we also receive the current state so we don&rsquo;t have to call getState ourself. replaceReducer is kind of an advanced API and it swaps the reducer currently used by the store. I personally never used this method. Reducer The reducer function is probably the most beautiful part of Redux. Even before that I was interested in writing pure functions with an immutability in mind but Redux forced me to do it. There are two characteristics of the reducer that are quite important and without them we basically have a broken pattern. (1) It must be a pure function - it means that the function should return the exact same output evert time when the same input is given. (2) It should have no side effects - stuff like accessing a global variable, making an async call or waiting for a promise to resolve have no place in here. Here is a simple counter reducer: const counterReducer = function (state, action) { if (action.type === ADD) { return { value: state.value + 1 }; } else if (action.type === SUBTRACT) { return { value: state.value - 1 }; } return { value: 0 }; }; There are no side effects and we return a brand new object every time. We accumulate the new value based on the previous state and the incoming action type. Wiring to React components If we talk about Redux in the context of React we almost always mean react-redux module. It provides two things that help connecting Redux to our components. (1) &lt;Provider&gt; component - it&rsquo;s a component that accepts our store and makes it available for the children down the React tree via the React&rsquo;s context API. For example: <Provider store={ myStore }&gt; <MyApp /&gt; </Provider&gt; We usually have a single place in our app where we use it. (2) connect function - it is a function that does the subscribing for updates in the store and re-renders our component. It implements a higher-order component. Here is its signature: connect( [mapStateToProps], [mapDispatchToProps], [mergeProps], [options] ) mapStateToProps parameter is a function that accepts the current state and must return a set of key-value pairs (an object) that are getting send as props to our React component. For example: const mapStateToProps = state =&gt; ({ visible: state.visible }); mapDispatchToProps is a similar one but instead of the state receives a dispatch function. Here is the place where we can define a prop for dispatching actions. const mapDispatchToProps = dispatch =&gt; ({ changeVisibility: value =&gt; dispatch(changeVisibility(value)) }); mergeProps combines both mapStateToProps and mapDispatchToProps and the props send to the component and gives us the opportunity to accumulate better props. Like for example if we need to fire two actions we may combine them to a single prop and send that to React. options accepts couple of settings that control how how the connection works. Simple counter app using Redux Let&rsquo;s create a simple counter app that uses all the APIs above. The &ldquo;Add&rdquo; and &ldquo;Subtract&rdquo; buttons will simply change a value in our store. &ldquo;Visible&rdquo; and &ldquo;Hidden&rdquo; will control its visibility. Modeling the actions For me, every Redux feature starts with modeling the action types and defining what state we want to keep. In our case we have three operations going on - adding, subtracting and managing visibility. So we will go with the following: const ADD = \'ADD\'; const SUBTRACT = \'SUBTRACT\'; const CHANGE_VISIBILITY = \'CHANGE_VISIBILITY\'; const add = () =&gt; ({ type: ADD }); const subtract = () =&gt; ({ type: SUBTRACT }); const changeVisibility = visible =&gt; ({ type: CHANGE_VISIBILITY, visible }); Store and its reducers There is something that we didn&rsquo;t talk about while explaining the store and reducers. We usually have more then one reducer because we want to manage multiple things. The store is one though and we in theory have only one state object. What happens in most of the apps running in production is that the application state is a composition of slices. Every slice represents a part of our system. In this very small example we have counting and visibility slices. So our initial state looks like that: const initialState = { counter: { value: 0 }, visible: true }; We must define separate reducers for both parts. This is to introduce some flexibility and to improve the readability of our code. Imagine if we have a giant app with ten or more state slices and we keep working within a single function. It will be too difficult to manage. Redux comes with a helper that allows us to target a specific part of the state and assign a reducer to it. It is called combineReducers: import { createStore, combineReducers } from \'redux\'; const rootReducer = combineReducers({ counter: function A() { ... }, visible: function B() { ... } }); const store = createStore(rootReducer); Function A receives only the counter slice as a state and needs to return only that part. Same for B. Accepts a boolean (the value of visible) and must return a boolean. The reducer for our counter slice should take into account both actions ADD and SUBTRACT and based on them calculates the new counter state. const counterReducer = function (state, action) { if (action.type === ADD) { return { value: state.value + 1 }; } else if (action.type === SUBTRACT) { return { value: state.value - 1 }; } return state || { value: 0 }; }; Every reducer is fired at least once when the store is initialized. In that very first run the state is undefined and the action is { type: \"@@redux/INIT\"}. In this case our reducer should return the initial value of our data - { value: 0 }. The reducer for the visibility is pretty similar except that it waits for CHANGE_VISIBILITY action: const visibilityReducer = function (state, action) { if (action.type === CHANGE_VISIBILITY) { return action.visible; } return true; }; And at the end we have to pass both reducers to combineReducers so we create our rootReducer. const rootReducer = combineReducers({ counter: counterReducer, visible: visibilityReducer }); Selectors Before moving to the React components we have to mention the concept of a selector. From the previous section we know that our state is usually divided into different parts. We have dedicated reducers to update the data but when it comes to fetching it we still have a single object. Here is the place where the selectors come in handy. The selector is a function that accepts the whole state object and extracts only the information that we need. For example in our small app we need two of those: const getCounterValue = state =&gt; state.counter.value; const getVisibility = state =&gt; state.visible; A counter app is too small to see the real power of writing such helpers. However, in a big project is quite different. And it is not just about saving a few lines of code. Neither is about readability. Selectors come with these stuff but they are also contextual and may contain logic. Since they have access to the whole state they are able to answer business logic related questions. Like for example &ldquo;Is the user authorize to do X while being on page Y&rdquo;. This may be done in a single selector. React components Let&rsquo;s first deal with the UI that manages the visibility of the counter. function Visibility({ changeVisibility }) { return ( <div&gt; <button onClick={ () =&gt; changeVisibility(true) }&gt; Visible </button&gt; <button onClick={ () =&gt; changeVisibility(false) }&gt; Hidden </button&gt; </div&gt; ); } const VisibilityConnected = connect( null, dispatch =&gt; ({ changeVisibility: value =&gt; dispatch(changeVisibility(value)) }) )(Visibility); We have two buttons Visible and Hidden. They both fire CHANGE_VISIBILITY action but the first one passes true as a value while the second one false. The VisibilityConnected component class gets created as a result of the wiring done via Redux&rsquo;s connect. Notice that we pass null as mapStateToProps because we don&rsquo;t need any of the data in the store. We just need to dispatch an action. The second component is slightly more complicated. It is named Counter and renders two buttons and the counter value. function Counter({ value, add, subtract }) { return ( <div&gt; <p&gt;Value: { value }</p&gt; <button onClick={ add }&gt;Add</button&gt; <button onClick={ subtract }&gt;Subtract</button&gt; </div&gt; ); } const CounterConnected = connect( state =&gt; ({ value: getCounterValue(state) }), dispatch =&gt; ({ add: () =&gt; dispatch(add()), subtract: () =&gt; dispatch(subtract()) }) )(Counter); We now need both mapStateToProps and mapDispatchToProps because we want to read data from the store and dispatch actions. Our component receives three props - value, add and subtract. The very last bit is an App component where we compose the application. function App({ visible }) { return ( <div&gt; <VisibilityConnected /&gt; { visible &amp;&amp; <CounterConnected /&gt; } </div&gt; ); } const AppConnected = connect( state =&gt; ({ visible: getVisibility(state) }) )(App); We again need to connect our component because we want to control the visibility of the counter. The getVisibility selector returns a boolean that indicates weather CounterConnected will be rendered or not. Final thoughts Redux is a wonderful pattern. Over the years the JavaScript community developed the idea and enhanced it with couple of new terms. I think a typical redux application looks more like this: By the way we didn&rsquo;t mention the side effects management. It is a whole new story with its own ideas and solutions. We can conclude that Redux itself is a pretty simple pattern. It teaches very useful techniques but unfortunately it is very often not enough. Sooner or later we have to introduce more concepts/patterns. Which of course is not that bad. We just have to plan for it.收起
显示全部文字 查看全文
作者/
时间/2018-04-06 05:00:00

What to Learn First

Getting Started So you want to learn how to code websites but are unsure where to start? Well, CodePen is a fantastic site/tool to use to help you learn your way around the basic site scripting languages. HTML Essentially HTML (Hypertext Markup Language) is the bare bones of a website. This is as basic as it gets. If you are just starting to code I suggest learning HTML first before any other scripting language as this will assist you in understanding how websites are formatted. &lt;!DOCTYPE html&gt; &lt;html&gt; &lt;head&gt;&lt;/head&gt; &lt;title&gt;&lt;/title&gt; &lt;header&gt;&lt;/header&gt; &lt;p&gt;&lt;/p&gt; &lt;/html&gt; Above is a simple html page, of course if you were to open a page with that exact code, the page would be blank. To briefly explain how html works, there are tags for all that is html. Even an html tag to tell the site that you are using the language html. The next is the head tag which is where you can link other scripts to other documents that you want to integrate into your html code. This will come later on so no need to worry about that. The title tag is simply the words on the tab at the top of the page. header is a the header of an article or website. A prime example of this is on News websites, they use a header to introduce the name of the article. p is simply a paragraph section. Remember that all of these tags need to be closed using the same tag but with a / before the word or letter. Example: &lt;/html&gt; CSS Cascading Style Sheets other known as CSS is what makes a website visually appealing. Usually this involved shapes, fonts and animations (keyframes). Below is a prime example of what can be done with just CSS. If you look at the example above, CSS is basically the meat of a webpage. A simple way to start out is by understand how to implement it in your html. This can be done by going to your &lt;head&gt; and inserting where the .css document is. link rel="stylesheet" href="style.css"&gt; Once your style sheet or whatever you choose to call your .css file is linked to your html page you can start adding code to your .css file. Make sure that you have elements in your .html file that you want to edit such as a paragraph &lt;p&gt; or a &lt;div&gt;. Here is a simple portion of code that will show what a div's css code would look like. .div { margin: 0 auto; position: relative; background: #202B33; height: 200px; width: 200px; } This would link to this portion of your html code &lt;div class="div"&gt; &lt;/div&gt; Conclusion Whilst this information may be a lot at once, if you grab anything from this it would be to start with learning HTML. Once you're comfortable with that move onto CSS. There are endless tutorials on https://stackoverflow.com if you're confused or stuck. Just stick to it!收起
显示全部文字 查看全文
作者/Conner
时间/2018-04-04 09:42:45

15 Interesting JavaScript and CSS Libraries for April 2018

We share with you a collection of awesome and free resources for this April.
查看全文
作者/Georgi Georgiev
时间/2018-04-03 22:54:40

Protecting users from extension cryptojacking

As the extensions ecosystem continues to evolve, we remain focused on empowering developers to build innovative experiences while keeping our users as safe as possible. Over the past few months, there has been a rise in malicious extensions that appear to provide useful functionality on the surface, while embedding hidden cryptocurrency mining scripts that run in the background without the user’s consent. These mining scripts often consume significant CPU resources, and can severely impact system performance and power consumption.&nbsp;The chart above shows a recent example of CPU overutilization from hidden coin mining in an extension.&nbsp;Until now, Chrome Web Store policy has permitted cryptocurrency mining in extensions as long as it is the extension’s single purpose, and the user is adequately informed about the mining behavior. Unfortunately, approximately 90% of all extensions with mining scripts that developers have attempted to upload to Chrome Web Store have failed to comply with these policies, and have been either rejected or removed from the store.Starting today, Chrome Web Store will no longer accept extensions that mine cryptocurrency. Existing extensions that mine cryptocurrency will be delisted from the Chrome Web Store in late June. Extensions with blockchain-related purposes other than mining will continue to be permitted in the Web Store.The extensions platform provides powerful capabilities that have enabled our developer community to build a vibrant catalog of extensions that help users get the most out of Chrome. Unfortunately, these same capabilities have attracted malicious software developers who attempt to abuse the platform at the expense of users. This policy is another step forward in ensuring that Chrome users can enjoy the benefits of extensions without exposing themselves to hidden risks.Posted by James Wagner, Extensions Platform Product Manager收起
显示全部文字 查看全文
作者/Chrome Blog
时间/2018-04-03 01:01:21

GSAP getRatio()

There is a hidden feature with TweenMax that you may never have noticed. All the easings included in the library are coming with the very useful getRatio() function. If we check the docs, here is the official definition of this function: Translates the tween's progress ratio into the corresponding ease ratio. In other words, this function returns to you the corresponding value from a linear easing to a custom easing of your choice. Here is an example with Power2.easeOut : Power2.easeOut.getRatio(0) // Returns 0 Power2.easeOut.getRatio(0.33) // Returns 0.69 Power2.easeOut.getRatio(0.5) // Returns 0.87 Power2.easeOut.getRatio(1) // Returns 1 We can translate those values into a graph to have a more visual idea of this concept. Let's see how this feature can be used for an animation. On the demo below I'm drawing 50 dots on the same Y axis. For every dot, its X position is based on the ratio of the chosen easing. Try changing the easing to see how it affects the animation ! Here is the important portion of the code from the demo with some comments to explain how it work. You may notice that the code exactly the same since I have to handle some UI for the demo. // First we select all the spans from the container var dots = document.querySelectorAll('.container span'); // We define the easing we want to use var easing = Power2.easeOut; // We define the duration wanted for the animation var duration = 4; // Then we create a Timeline to create a loop animation var tl = new TimelineMax({repeat: -1, repeatDelay: 1.5}); // We make sure all the dots are hidden tl.set(dots, { opacity: 0 }); // We loop through all the dots to define the timing when they should be displayed for (var i = 0; i &lt; dots.length; i++) { // We calculate the ratio based on the amount of dots // To make sure we have a 0 &amp; a 1 value, we should subtract one from the amount of dots var ratio = i / (dots.length - 1); // We add a tween in our timeline to display the dots tl.set(dots[i], { opacity: 1, // The left position is calculated from the easing we picked left: easing.getRatio(ratio) * 100 + '%' // The moment when the dot should appear is the equal of the ratio times the duration }, ratio * duration); } This is nice but how can this be useful to me ? I picked a few demos for your inspiration ! This feature can be applied to much more than timelines ;) Demo 1 This demo is using the same logic as the demo above but instead of using the ratio as the X position, it is the delay for every dot that is dynamic. This creates an effect where the dots are appearing slower at the beginning but faster in the end. Demo 2 Blake Bowen created this awesome demo to explain how you could animate waves using GSAP. You can find more info on this thread on the official GSAP forum. Demo 3 On this ThreeJs demo I'm using the getRatio() function to position the vertices. I hope you enjoyed this short post and you learned something new with GSAP ✌️ – Mamboleoo收起
显示全部文字 查看全文
作者/Louis Hoebregts
时间/2018-03-31 04:32:18

Super-powered layouts with CSS Variables + CSS Grid

We’ve been using CSS Grid in production at Mud for a few months now and I absolutely love the flexibility it’s giving me when coding layout. For so long we've got along without a true layout solution for the web - hacking it with floats and flexbox was just how we did things. But now, I honestly cannot imagine life without Grid! One thing that’s only come to my full attention more recently is CSS Variables (or Custom Properties). CSS Variables work a bit like variables in Sass and other preprocessors. The main difference is they’re compiled in the browser, unlike preprocessor variables, which are compiled into fixed CSS values before they hit the browser. CSS Variables are true dynamic variables that can be updated on the fly, either in your stylesheet or with JavaScript, which makes them super versatile. If you’re familiar with Javascript, I like to think of the difference between preprocessor variables and CSS Variables as similar to the difference between const and let - they both serve different purposes. CSS Variables can have a whole host of useful applications (such as theming, for one). One way I’ve been looking at making use of CSS Variables recently is in layouts using CSS Grid where I need to redefine my grid-template-rows and grid-template-columns properties at different breakpoints. Here’s an example in the following pen, where I’ve used Sass variables to define my small and large column widths, which I’m passing into the grid-template-rows property. I’m doing the same with the grid-gap property, so that my gutters increase in size for each breakpoint: As you can see, I basically have to write out the entire block of code again within the media query in order to pass in the second variable, as the variable is fixed once defined. (I could of course use a mixin, but the net effect is the same - a bigger chunk of code.) With CSS Variables I can down on the amount of code, as I can simply update my variable inside the media query and the browser recalculates my grid. Ten lines of (Sass) code may not seem like a huge saving, but the code is so much more readable - instead of having to add media queries in several places to deal with our new variables I can just declare them at the beginning of the code for that component and not have to worry about making sure I’ve replaced every value where it’s being used: One thing I’ve found with using CSS Grid is the syntax is quite verbose and it’s not always simple to see exactly what’s going on quickly and easily, especially with a complex grid. But using CSS Variables in this example I can set variables for the size and co-ordinates of Grid items and only write out the grid-column and grid-row properties once. This to me is a lot clearer than writing the full properties out every time, and very easy to see at a glance where we’re placing any grid item. Things get even more interesting when we add JavaScript into the mix! In the example above I’m using JavaScript to loop over the grid items and update the variables with a random value (within our grid parameters) each time the button is clicked. No added classes or extra CSS needed! (Please note, this is a work-in-progress proof-of-concept, don’t judge my JS ;) ) In the example below I’m using user inputs to dynamically change our grid items. All that's getting updated here are the three variables for the x and y coordinates and the size of the grid item. So many possibilities! Browser support At the moment CSS Variables are supported in 88% of browsers worldwide – Internet Explorer 11 and below being the obvious exception. That’s roughly the same as support for Grid Layout, which means it’s fairly simple to test for support using feature queries. You can use an @supports declaration like this to test for support for CSS Variables: @supports(--css: variables) { .my-div { --size: 2; --posX: 3; grid-column: var('--posX') / span var('--size'); } } (See this example pen by SitePoint) I hope this gives you a little taste of what's possible with CSS Variables!收起
显示全部文字 查看全文
作者/Michelle Barker
时间/2018-03-30 09:36:44

Freebie: 3 Amazing Bootstrap 4 Gallery Templates

A pack of 3 free Lightbox image galleries with interesting on-hover effects.
查看全文
作者/Georgi Georgiev
时间/2018-03-27 22:22:19

Organizing a CodePen meetup

Organizing any meetup can be a huge undertaking for someone: extra stress, time and responsibilities. Hopefully this post helps you with your own event by covering my process for setting up CodePen Chicago: recon, promotion, event day, and closure. You can find more CodePen meetup info on Github, CodePen Meetups, feel free to contribute with any updates or fork for your own needs :D Here's a Trello board checklist, CodePen meetup. Recon Begin by contacting support@codepen.io to make sure no one else is organizing, they'll get your sponsorship with MediaTemple arranged and you'll get sweet t-shirts, water bottles, pens, stickers and more :D Next gather data on other meetups that overlap with the CodePen community, I schedule around the front end development/design community in Chicago: JavaScript Meetup, A11YChi, Friends IRL, Design Football, React Meetup, etc. A network of peers and friends will help with securing a space, sponsorships, promotion and an audience. You can promote through tech communities, LinkedIn, Twitter, Meetup groups and other organizers. Promotion During promotion mention all the benefits of the event space: accessibility, food, beverages, childcare, special guests, parking, location and etc. Review content for promotion with sponsors, co-organizers, presenters and those you feel could be impacted by the messaging. Give credit where it's due, if someone has secured a sponsorship, space or presenting make sure to give them credit for helping. Event Day Send a reminder email the day of the event and if there's a cut off day for the RSVP list required because of building security. I arrive 30 minutes before start time to confirm wifi access, setup the equipment and test the AV. Make sure the space is accessible, food restrictions/allergies are accomidated, enough garbage cans for easier clean up and signage directing anyone to the space. Using the same computer is useful for tracking the presenters through browser history and if you are presenting from a pro account, you can use presentation mode. Allow everyone to get settled, 15-30 minutes from start time. Photograph, document the presenters and audience with a recap of the event. I encourage new presenters with some of the sweet swag, remember always be positive and encouraging, make it an inclusive space. Closure Write up a post with the event, presenters, photos and thank yous, you can find examples of other CodePen meetup posts if you need some inspiration. Make sure to promote it on Twitter and an email list, you can collect that through attendees when using vnite. Remember let there be code, fun and friendship :D收起
显示全部文字 查看全文
作者/Brian Montana
时间/2018-03-27 08:59:40

Scheduling Jekyll posts with Netlify and AWS

Not too long ago I moved this site from a custom setup on Amazon Web Services (AWS) to Netlify[1]. My AWS setup was a bit cumbersome, consisting of a Jenkins machine that pulled from a private GitHub repository, built the site using Jekyll[2], and published the result to S3. The benefit of this setup over...收起
显示全部文字 查看全文
作者/Nicholas C. Zakas
时间/2018-03-27 08:00:00

What I've Learned Validating with Joi

I’ll be honest, despite all of my experience as a front-end developer I haven’t had a lot of projects that dealt heavily with forms and data. Form validation was just something I never really had to work with much. My most recent project, however, is entirely form- and data-driven and I needed a way to easily handle front-end validation. For this, I turned to Joi. Joi is a validation library that allows you to build schemas to validate JavaScript objects. And what that generally means to me is Joi provides methods to easily validate common data types, such as e-mail addresses and phone numbers. But I’ve also learned that it allows you to easily validate less common data and complex data structures. And it was here, in Joi’s simplification of complex validation, where I found the urge to share what I’ve learned. Setting Up For this project, which consisted of React, Redux, and TypeScript, the validation needed to occur on the front end in the browser. Because of this I leveraged both Joi and Joi-Browser. yarn add joi --dev &amp;&amp; yarn add joi-browser --dev With the libraries installed Joi can be imported into your validation file and the writing of schemas can begin. import * as Joi from ‘joi-browser'; When validating with Joi, two pieces of data are needed: 1) The data object to validate 2) The Joi schema Joi.validate(data, schema, [options]); An optional third argument could be supplied to customise the validation behaviour but I won’t be covering that in this post. The Basics Validating Strings This particular project consisted of multiple forms with general information fields — the user’s name, address, e-mail, and phone number. These fields are pretty straight forward and quite fittingly so is the validation. Let’s take a look at an example of some data: const data = { name: 'Sydney Prescott', address: '1996 Woodsboro Ln', email: 'sydney.prescott@woodsborocc.edu', phone: '2135551997' }; With this general data structure, we can begin writing our Joi schema for validation. Let’s begin with the strings. const schema = Joi.object().keys({ name: Joi.string().required(), address: Joi.string().required(), email: Joi.string().email().required() }); One thing I really like about Joi is how it reads. From the schema above it is pretty clear to see what we’re expecting of each property. Additionally, by adding the required() method we can quickly organise important data while being able to double up on the required property on form fields themselves for extra security. The address field, however, required additional consideration. While living in the States I didn’t think much about additional characters outside of our alphabet. Having moved to Finland, though, made me realise that I must now account for values that have characters such as Ää and Öö. Luckily, Joi provides additional ways to support such circumstances. address: Joi .string() .trim() .regex(/^[a-z\d\s\-\.\,]*$/i) .max(100) .required() The schema above introduces a couple nice options. First, the trim() method will remove any trailing spaces from the value. The max() method is also used to limit the length of the value to 100 characters. But the primary method I’d like to draw attention to here is regex(). This method allows greater control over what values are supported — virtually extending the default string() validation and adding custom behaviour on top. If you had noticed, our data object stores the phone number as a string. Let’s see how we can leverage the regex() method in our schema for this case. phone: Joi.string().trim().regex(/^[0-9]{7,10}$/).required(); By using the regex() method here, we can validate the string to ensure its value is 7–10 characters all of which fall between 0 and 9. But you won’t always be storing phone numbers as strings. Eventually, validation for number fields will need to written and Joi makes this just as direct. Validating Numbers Let’s look at the following example data: const data = { salary: 48000, age: 30 }; Assuming we’re looking for users between the ages of 18 and 65 our schema could look like the following: const schema = Joi.object().keys({ salary: Joi.number().required(), age: Joi.number().min(18).max(65).required() }); Again, the readability of Joi is a big selling point as the use of the min() and max() methods quickly convey how we’re validating our data. However, we won’t always have such defined ranges like 18 and 65. So how can data be validated against other data values? Validate Against Data References In this particular project, which deals with applying for a loan, the user is asked to specify both their total wealth as well as their total savings and investments. Because a person’s savings is part of their total wealth, the savings field should never be greater than the totalWealth value. But since we won’t know those values until the time of validation, Joi provides the ref() method for situations exactly like this. const data = { totalWealth: 5000, savings: 10000 }; const schema = Joi.object().keys({ totalWealth: Joi.number().required(), savings: Joi.number().max(Joi.ref('totalWealth')).required() }); Inside of the max() method the value of totalWealth is referenced by using Joi’s ref() method and passing in the key of the target field. With this schema our data object would error. Conditional Validation There’s a fair chance you’ve either used or built a form with conditional fields. For example, why show the user fields concerning credit card debt if the user selected “No” to owning any credit cards? Our validation should follow the same logic — only validate certain fields when other criteria is met. const data = { hasCreditCards: true, creditCardDebt: 750, creditCardMonthlyPayment: 75 }; With the data model above and understanding our need for conditional validation, let’s look at our Joi schema. const schema = Joi.object().keys({ hasCreditCards: Joi.bool().required, creditCardDebt: Joi.number().when('hasCreditCards', { is: true, then: Joi.number().min(0).required() }), creditCardMonthlyPayment: Joi.number().when('hasCreditCards', { is: true, then: Joi.number().min(0).required() }) }); In this example, the when() method is leveraged. Again, Joi reads quite clearly  —  when hasCreditCards is true then validate using the following schema. But let’s say we wanted to expand our data model to include an array of credit card objects, all containing their own individual values. const data = { hasCreditCards: true, allCreditCards: [{ type: 'Visa', balance: 250, payment: 25 }, { type: 'Discover', balance: 1200, payment: 100 }] }; In this case, we have an array with a variable number of objects that we need to validate only if the user hasCreditCards. Let’s start with what we know: const schema = Joi.object().keys({ hasCreditCards: Joi.bool().required(), allCreditCards: Joi.array().when('hasCreditCards', { is: true, then: ... } }); Again, using the when() method, we can conditionally validate the allCreditCards array. The next step is to validate the individual properties of each object within the array. then: Joi.array().items({ type: Joi.string().required(), balance: Joi.number().required(), payment: Joi.number().required() }) By using the items() method, we define the contents of the array. In this specific case, the items are an object but this method can support any combination of comma-separated Joi schemas. For example, if our array would only contain a required string and an optional number our schema could look like this: Joi.array().items(Joi.string().required(), Joi.number()) Back to our original credit card example, though. Let’s say we want to have more control over which credit card providers are supported. For example, my Discover card isn ‘t accepted anywhere in Finland (like literally, anywhere!). So how could we write our validation to include and/or exclude particular values? then: Joi.array().items({ type: Joi .string() .valid(['Visa', 'Mastercard']) .invalid('Discover') .required(), balance: Joi.number().required(), payment: Joi.number().required() }) By using the valid() and invalid() methods greater control can be applied to the validation. This can be nicely paired with enum values as well. Now, for it all together. const schema = Joi.object().keys({ hasCreditCards: Joi.bool().required(), allCreditCards: Joi.array().when('hasCreditCards', { is: true, then: Joi.array().items({ type: Joi .string() .valid(['Visa', 'Mastercard']) .invalid('Discover') .required(), balance: Joi.number().required(), payment: Joi.number().required() }) }) }); Cue the record scratch because yet again I love how quickly this can be read and understood. My hat goes off to the work done with the naming within Joi. Joi is capable of doing so much more than what I’ve covered here and luckily, their documentation (found here) is terrific. I feel this project has given me a great crash course on validation and using Joi to do some things that would otherwise be quite challenging. Well done, Joi.收起
显示全部文字 查看全文
作者/Daniel Yuschick
时间/2018-03-27 06:46:05

NADCAST.12 с Димитър Димитров

Епизод номер 12 е с Димитър Димитров (Митьо). Поговорихме си за менторството и за това как трябва да се подхожда към начинаещите програмисти. Имаше и малко DevOps даже :)
查看全文
作者/
时间/2018-03-22 06:00:00

Chrome 66 Beta: CSS Typed Object Model, Async Clipboard API, AudioWorklet

Unless otherwise noted, changes described below apply to the newest Chrome Beta channel release for Android, Chrome OS, Linux, macOS, and Windows. View a complete list of the features in Chrome 66 on ChromeStatus.The ImageBitmap Rendering Context for &lt;canvas&gt;Historically, rendering an image to a canvas has involved first creating an &lt;img&gt; tag and then rendering its contents to a canvas. This causes multiple copies of the image to be stored in memory. A new rendering context streamlines the display of ImageBitmap objects by avoiding memory duplication and rendering them more efficiently.This example shows how to do this using an ImageBitmapRenderingContext. This essentially transfers ownership of an image's pixels. This example does so from a blob to a &lt;canvas&gt;, but pixels can be moved between &lt;canvas&gt; elements as well. Note that the blob is compressed so it is not a full copy in memory.const image = await createImageBitmap(imageBlob);const canvas = document.createElement('canvas');const context = canvas.getContext('bitmaprenderer');context.transferFromImageBitmap(image);canvas.toBlob((outputJPEGBlob) =&gt; { // Do something with outputJPEGBlob.}, 'image/jpeg');If this were done without createImageBitmap(), the imageBlob would be lazily decoded, which would cause jank. On the other hand createImageBitmap() is asynchronous which allows you to decode it completely before using it and avoiding jank. For example, a WebGL game could use this to load new textures on the fly as gameplay progresses.CSS Typed Object ModelHistorically, developers wanting to manipulate CSS properties have had to manipulate strings only for the browser to then convert it back to a typed representation. What made things worse was when developers tried to read the value of a CSS property in Javascript, this typed value was converted back to a string. In version 66, Chrome implements the CSS Typed Object Model (OM) Level 1, a part of Houdini, for a subset of CSS properties. Typed OM reduces this burden on both the developer and browser by exposing CSS values as typed JavaScript objects rather than strings. Along with allowing the performant manipulation of values assigned to CSS properties, Typed OM allows developers to write more maintainable and easy to understand code. A brief example illustrates the point. Previously if I wanted to set the opacity of an element I could do this:el.style.opacity = 0.3;el.style.opacity === "0.3"With CSSOM:el.attributeStyleMap.set("opacity", CSS.number("0.3"));el.attributeStyleMap.get("opacity").value === 0.3The returned values above are of type CSSUnitValue, which are easier to manipulate than strings. Asynchronous Clipboard APIThe new asynchronous clipboard API provides a promise-based means of reading from and writing to the clipboard. It's simpler than the old execCommand('copy') API released in Chrome 43 and integrates with the Permissions API. Future Chrome releases will also support copy/paste of richer types of data, including images.To get a taste of this API, lets do simple write and read operations with text.try { await navigator.clipboard.writeText("Hello, clipboard.");} catch { console.error("Unable to write to clipboard.");}Similarly, to read text back:const data = await navigator.clipboard.readText();console.log("From the clipboard:", data);For more information, including how to use security and permissions with the API, read Unblocking Clipboard Access and check out our sample.AudioWorkletThe legacy ScriptProcessorNode was asynchronous and required thread hops, which could produce an unstable audio output. The AudioWorklet&nbsp;object provides a new synchronous JavaScript execution context which allows developers to programmatically control audio without additional latency and higher stability in the output audio.You can see example code in action along with other examples at Google Chrome Labs.In addition to AudioWorklet, other worklet API are being built. PaintWorklet&nbsp;was released in Chrome 65/Opera 52. An AnimationWorklet is planned. ScriptProcessorNode will be deprecated some time after AudioWorklet ships.Other Features in this ReleaseBlink &gt; AnimationThe add and accumulate compositing operations are intended for building modularized animations. The add and accumulate keywords will be supported in Chrome soon. Until then, they will no longer throw errors. This is to maintain compatibility with Firefox and other implementations.Blink &gt; CSSCSS has two new features.The mathematical expressions calc(), min(), and max() are now supported in media queries, as required by the CSS Values and Units Module Level 4 specification. This change brings them in line with other types of rules where these functions are allowed anywhere a number is allowed.Floating point values are now allowed in the rgb() and rgba() functions.Blink &gt; Feature PolicyBy default, the deviceorientation, deviceorientationabsolute, and devicemotion events are now restricted to top-level document and same-origin subframes, the same as if the feature policy for those features were set to 'self'. To modify this behavior, explicitly enable or disable the specific feature.Blink &gt; File APIThe File API now results in a network error instead of a 404 when attempting to read from an invalid or non-existing blob URL.Blink &gt; FormsHTML forms have two new features.The &lt;textarea&gt; element and the &lt;select&gt; element now support the autocomplete attribute as required by the specification.A mutable checkbox now fires three events as required by the HTML specification: a click event, then an input event, then a change event. Formerly only the click and change events were fired.Blink &gt; FullscreenIf a page in fullscreen mode opens a popup and calls window.focus(), that page exits full screen. This does not occur if the popup receives focus some other way.Blink &gt; GetUserMediaA new method on the MediaStreamTrack interface called getCapabilities()returns a MediaTrackCapabilities object, which specifies the values or range of values which each constrianable property. Capabilities vary by device. Blink &gt; JavaScriptThere are several JavaScript changes.The Function.prototype.toString()&nbsp;function now returns exactly what is written in the source code. This includes whitespace and other text that may have been used. For example, if there is a comment between the function keyword and the function name, the comment is now returned in addition to the keyword and name.JSON is now a syntactic subset of ECMAScript, which allows line separator (U+2028) and paragraph separator (U+2029) symbols in string literals.The catch clause of a try statement can now be used without a parameter.String.prototype.trimStart() and String.prototype.trimLeft() are now available as the standards-based way of trimming whitespace from strings, in addition to String.prototype.trim() which was already implemented. The non-standard trimLeft() and trimRight() remain as aliases of the new methods for backward compatibility.The Array.prototype.values()&nbsp;method returns a new array iterator object that contains the values for each index in the array.Blink &gt; LayoutLayout has two new features.The grid prefix has been removed from the CSS gutter properties:grid-gap becomes gapgrid-row-gap becomes row-gapgrid-column-gap becomes column-gapThe default value for all three is normal and the prefixed properties are aliases of the new ones. Note that column-gap property already exists and is used by css-multicol. Elements with the display properties table-row, table-row-group, table-header-group, table-footer-group, table-cell, and table-caption that have a transform property are now containing blocks for fixed position elements. Blink currently does not make &lt;tr&gt;, &lt;tbody&gt;, &lt;tfoot&gt;, and &lt;thead&gt; be containing blocks for fixed-position elements.Blink &gt; MediaMedia has two new features.As announced earlier, autoplay is now allowed only when either the media won't play sound, after the user clicks or taps on the site, or (on desktop) if the user has previously shown an interest in media on the site. This will reduce unexpected video playbacks with sound when first opening a web page.The Media Capabilities, Decoding Info API allows websites to get more information about the decoding abilities of the client. This enables more informed selection of media streams for the user, avoiding scenarios such as where the client is unable to smoothly and power-efficiently decode a resolution that might have been picked based only on available bandwidth and screen size.Blink &gt; NetworkThe Fetch API has two new features.The Request object now supports a keepalive&nbsp;property which allows a fetch to continue after a tab is closed. This feature is invoked by passing a boolean in the constructor's initialization object. Its value can be read back from the object itself. This property can be used with sendBeacon() as well.New AbortSignal and AbortController interfaces allow a fetch to be canceled. To accomplish this create an AbortController object and pass its signal property as an option to fetch. Calling abortController.abort() cancels the fetch. There's more information in our abortable fetch article, but a small code example is shown below.const controller = new AbortController();const signal = controller.signal;const requestPromise = fetch(url, { signal });// Abort the fetch:controller.abort();Blink &gt; ServiceWorkerService workers have two changes.A service worker can no longer respond to a request whose mode is same-origin with a response whose type is CORS. This is a security measure recently added to the Fetch specification.FetchEvent.clientId now returns an empty string instead of null when it isn't set. For example, this can occur during a navigation request.Blink &gt; WebRTCChrome now supports the RTCRtpSender.dtmfattribute per the specification. This replaces the CreateDTMFSender() function which has not yet been deprecated. Deprecations and Interoperability ImprovementsBlink &gt; CSSThe object-position and perspective-origin properties no longer accepts three-part values such as top right 20%. This change also applies to basic shapes and gradients. Valid position values must always have 1, 2, or 4 parts.Blink &gt; HTMLFollowing a specification change, ImageCapture.prototype.setOptions() has been removed.Blink &gt; InputFollowing a specification change, document.createTouch() and document.createTouchList() have been removed.Blink &gt; Web AudioFollowing a specification change, automatic dezippering of AudioParam.prototype.value changes was removed from Chrome. If you need to smooth the value of AudioParam changes, use AudioParam.prorotype.setTargetAtTime().Posted by Naina Raisinghani收起
显示全部文字 查看全文
作者/Chrome Blog
时间/2018-03-22 03:18:04

8 Awesome and Free PHP Books

In this article we share with you a list of interesting books for learning PHP.
查看全文
作者/Georgi Georgiev
时间/2018-03-21 17:58:50